金狮贵宾会

登录
免费开通

微信小程序打包插件开发体验

微信官方已经开放了插件的共享,,,那么关于微信小程序开发来说,,,怎样做到小程序打包插件呢?????下面来看看文章。。

微信小程序打包插件开发体验

若是你看过文档,,,相信你一定知道:

  • 每个插件必需要有 apply 要领,,,用于 webpack 引擎执行你想要执行的代码。。
  • 两个主要的工具 Compiler 和 Compilation,,,你可以在上面绑定事务钩子(webpack 执行到该方法的时间挪用),,,详细有哪些事务钩子可以阅读Compiler hooks。。
  • module 和 chunk 的关系,,,我们可以明确为每个文件都会有一个 module,,,而一个 chunk 则是由多个 module 来组成。。
  • webpack 整个打包流程有那些事务
  • 怎样写一个简朴的 loader

若是感受无从着手,,,可以继续看看我是怎样一步步开发并完善 mini-program-webpack-loader 来打包小程序的。。

小程序有一个牢靠的套路,,,首先需要有一个 app.json 文件来界说所有的页面路径,,,然后每个页面有四个文件组成:.js,,,.json,,,.wxml,,,.wxss。。以是我以 app.json 作为 webpack entry,,,当 webpack 执行插件的 apply 的时间,,,通过获取 entry 来知道小程序都有哪些页面。。

 

这里使用了两个插件 MultiEntryPlugin,,,SingleEntryPlugin。。为什么要这样做呢?????由于 webpack 会凭证你的 entry 设置(这里的 entry 不但是 webpack 设置里的 entry,,,import(), require.ensure() 都会天生一个 entry)来决议天生文件的个数,,,我们不希望把所有页面的 js 打包到一个文件,,,需要使用 SingleEntryPlugin 来天生一个新的 entry module;;;而那些静态资源,,,我们可以使用 MultiEntryPlugin 插件来处理,,,把这些文件作为一个 entry module 的依赖,,,在 loader 中设置 file-loader 即可把静态文件输出。。伪代码如下:

const MultiEntryPlugin = require('webpack/lib/MultiEntryPlugin');
 const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
 
 class MiniPlugin {
    apply (compiler) {
        let options = compiler.options
        let context = compiler.rootContext
        let entry = options.entry
        let files = loadFiles(entry)
        let scripts = files.filter(file => /\.js$/.test(file))
        let assets = files.filter(file => !/\.js$/.test(file))
        
       new  MultiEntryPlugin(context, assets, '__assets__').apply(compiler)
        
        scripts.forEach((file => {
            let fileName = relative(context, file).replace(extname(file), '');
            new SingleEntryPlugin(context, file, fileName).apply(compiler);
        })
    }
 }
复制代码

虽然,,,若是像上面那样做,,,你会发明最后会多出一个 main.js,,,xxx.js(使用 MultiEntryPlugin 时填的名字),,,main.js 对应的是设置的 entry 天生的文件,,,xxx.js 则是 MultiEntryPlugin 天生的。。这些文件不是我们需要的,,,以是需要去掉他。。若是熟悉 webpack 文档,,,我们有许多地方可以修改最终打包出来的文件,,,如 compiler 的 emit 事务,,,compilation 的 optimizeChunks 相关的事务都可以实现。。其实质上就是去修改 compilation.assets 工具。。

在 mini-program-webpack-loader 中就使用了 emit 事务来处理这种不需要输出的内容。。

 

小程序打包虽然没这么简朴,,,还得支持wxml、wxss、wxs和自界说组件的引用,,,以是这个时间就需要一个 loader 来完成了,,,loader 需要做的事情也很是简朴 —— 剖析依赖的文件,,,如 .wxml 需要剖析 import 组件的 src,,,wxs 的 src,,,.wxss 需要剖析 @import,,,wxs 的 require,,,最后在 loader 中使用 loadModule 要领添加即可。。自界说组件一最先在 add entry 方法的时间直接获取了,,,以是不需要 loader 来完成。。

 

这样做也没什么问题,,,可是开发体验是较量差的,,,如再添加一个自界说组件,,,一个页面,,,webpack 是无感知的,,,以是需要在页面中的 .json 爆发改变时检查是不是新增了自界说组件或者新增了页面。。这个时间遇到一个问题,,,自界说组件的 js 是不可通过 addModule 的方式来添加的,,,由于自界说组件的 js 必需作为自力的入口文件。。在 loader 中是做不了,,,以是实验把文件传到 plugin 中(由于 plugin 先于 loader 执行,,,以是是可以建设 loader 和 plugin 通讯的)。。

简朴粗暴的方式:

// loader.js
class MiniLoader {}

module.exports = function (content) {
    new MiniLoader(this, content)
}
module.exports.$applyPluginInstance = function (plugin) {
  MiniLoader.prototype.$plugin = plugin
}

// plugin.js
const loader = require('./loader')
class MiniPlugin {
    apply (compiler) {
        loader.$applyPluginInstance(this);
    }
}
复制代码

可是...。。文件是传到 plugin 了,,,可是再使用 SingleEntryPlugin 时你会发明,,,没效果。。由于在 compiler make 之后 webpack 已经不可感知新的 module 添加了,,,以是是没有用的,,,这个时间就需要凭证文档猜,,,怎么样才华让 webpack 感知到新的 module,,,凭证文档中的事务做要害字盘问,,,可以发明在编译完成的时间会挪用 compilation needAdditionalPass 事务钩子:

this.emitAssets(compilation, err => {
    	if (err) return finalCallback(err);
    
    	if (compilation.hooks.needAdditionalPass.call()) {
    		compilation.needAdditionalPass = true;
    
    		const stats = new Stats(compilation);
    		stats.startTime = startTime;
    		stats.endTime = Date.now();
    		this.hooks.done.callAsync(stats, err => {
    			if (err) return finalCallback(err);
    
    			this.hooks.additionalPass.callAsync(err => {
    				if (err) return finalCallback(err);
    				this.compile(onCompiled);
    			});
    		});
    		return;
    	}
    
    	this.emitRecords(err => {
    		if (err) return finalCallback(err);
    
    		const stats = new Stats(compilation);
    		stats.startTime = startTime;
    		stats.endTime = Date.now();
    		this.hooks.done.callAsync(stats, err => {
    			if (err) return finalCallback(err);
    			return finalCallback(null, stats);
    		});
    	});
    });
复制代码

若是在这个事务钩子返回一个 true 值,,,则可以使 webpack 挪用 compiler additionalPass 事务钩子,,,实验在这里添加文件,,,果真是可以的。。

 

虽然,,,小程序打包尚有些差别的地方,,,好比分包,,,怎样用好 splitchunk,,,就不在啰嗦了,,,当你最先以后你会发明有许多的要领来实现想要的效果。。

插件开发到这里差未几了,,,总的来说,,,webpack 就是变着名堂的回调,,,当你知道每个回调该做什么的时间,,,webpack 用起来就轻松了。。显着我不知道,,,由于在开发历程中遇到了一些问题。。

遇到的问题

1.怎样在小程序代码中支持 resolve alias,,,node_modules?????

既然是工具,,,虽然需要做更多的事情,,,有赞的小程序那么重大,,,若是支持 resolve alias,,,node_modules 可以使得项目更利便维护,,,或许你会说这不是 webpack 最基本的功效吗,,,不是的,,,我们虽然是希望可以在任何文件中使用 alias,,,node_modules 支持的不但仅是 js。。虽然这样做就意味着事情将变得重大,,,首先就是获取文件路径,,,必需是异步的,,,由于在 webpack 4 中 resolve 不再支持 sync。。其次就是小程序的目录名不可是 node_modules,,,这时就需要一种盘算相对路径的规则,,,照旧相对打包输出的,,,而不是相对目今项目目录。。

2.多个小程序项目的合并

有赞从小程序来讲,,,有微商城版,,,有零售版,,,以及公共版,,,其中大多基础功效,,,营业都是相同的,,,虽然不可再每个小程序在开发一次,,,以是这个工具具备合并多个小程序虽然是必需的。。这样的合并稍微又要比从 node_modules 中取文件重大一些,,,由于需要包管多个小程序合并后的页面是准确的,,,并且要包管路径稳固。。

这两个问题的最终的解决方案既是以 webpack rootContext 的 src 目录为基准目录,,,以该目录所在路径盘算打包文件的绝对路径,,,然后凭证入口文件的 app.json 所在目录的路径盘算出最终输出路径。。

exports.getDistPath = (compilerContext, entryContexts) => {
  /**
   * webpack 以 config 所在目录的 src 为打包入口
   * 以是可以凭证该目录追溯源文件地点
   */
  return (path) => {
    let fullPath = compilerContext
    let npmReg = /node_modules/g
    let pDirReg = /^[_|\.\.]\//g

    if (isAbsolute(path)) {
      fullPath = path
    } else {
      // 相对路径:webpack 最后天生的路径,,,打包入口外的文件都以 '_' 体现上级目录

      while (pDirReg.test(path)) {
        path = path.substr(pDirReg.lastIndex)
        fullPath = join(fullPath, '../')
      }

      if (fullPath !== compilerContext) {
        fullPath = join(fullPath, path)
      }
    }
    // 凭证 entry 中界说的 json 文件目录获取打包后所在目录,,,若是不可获取就返回原路径
    let contextReg = new RegExp(entryContexts.join('|'), 'g')

    if (fullPath !== compilerContext && contextReg.exec(fullPath)) {
      path = fullPath.substr(contextReg.lastIndex + 1)
      console.assert(!npmReg.test(path), `文件${path}路径过失:不应该还包括 node_modules`)
    }

    /**
     * 若是有 node_modules 字符串,,,则去模浚???槊
     * 若是 app.json 在 node_modules 中,,,那 path 不应该包括 node_modules 
     */

    if (npmReg.test(path)) {
      path = path.substr(npmReg.lastIndex + 1)
    }

    return path
  }
}
复制代码

3.怎样把子包单独依赖的内容打包到子包内

解决这个问题的要领是通过 optimizeChunks 事务,,,在每个 chunk 的依赖的 module 中添加这个 chunk 的入口文件,,,然后在 splitChunk 的 test 设置中检查 module 被依赖的数目。。若是只有一个,,,并且是被子包依赖,,,则打包到子包内。。

4.webpack 支持单文件失败

这是一个未解决的问题,,,当实验使用 webpack 来支持单文件的时间,,,似乎没那么利便:

  • 单文件拆分为四个文件后,,,可以使用 emitFile 和 addDependency 来建设文件,,,可是建设的文件不会执行 loader
  • 使用 loadModule 会由于文件系统不保存该文件会报错

小程序工具提供多类型商城/门店小程序制作,,,可视化编辑 1秒天生5步上线。。通过拖拽、拼接模浚???榻峁剐〕绦蛏坛且趁妫,,所看即所得,,,只需要美工就能做出细腻商城。。更多小程序市肆请审查:小程序市肆

微信小程序打包插件开发体验

 


【本站声明】
  1、本站文章中所选用的图片及文字泉源于网络以及用户投稿,,,由于未联系到知识产权人或未发明有关知识产权的挂号,,,若有知识产权人并不肯意我们使用,,,若是有侵权请连忙联系。。
  2、本网站差池文章中所涉及的内容真实性、准确性、可靠性认真,,,仅系客观性形貌,,,如您需要相识该类商品/服务详细的资讯,,,请您直接与该类商品/服务的提供者联系。。


KESION 金狮贵宾会软件

KESION 金狮贵宾会软件是海内领先的在线教育软件及私域社交电商软件服务提供商,,,恒久专注于为企业提供在线教育软件及社交电商SaaS平台解决方案。。
公司焦点产品云开店SaaS社交电商服务平台、在线教育SaaS服务平台、教育企业数字化SaaS云平台、企微营销助手、私有化自力安排品牌网校和在线教育咨询等。。

KESION 一直通过手艺立异,,,提供产品和服务,,,助力企业向数字化转型,,,通过科技驱动商业刷新,,,让商业变得更智慧!



▼点击进入金狮贵宾会官网相识更多



上/下篇
  • vue和微信小程序的区别、较量

  • 越来越多的小程序商城系统选择电商SAAS平台

换一换相关推荐
精选内容
热门精选
金狮贵宾会·宾至如归-尊贵显赫 金狮贵宾会·宾至如归-尊贵显赫 金狮贵宾会·宾至如归-尊贵显赫
【网站地图】
微信小程序打包插件开发体验 - KESION 金狮贵宾会