开门见山地说,小程序在日常开发中使用原生框架来开发还是挺不方便的,比如:
这样一来和日常开发前端页面的体验相比来说,简直就像在刀耕火种。 那么为了解决这些问题,我们能不能将前端开发中常用的 webpack 移植到小程序开发中呢? 当然可以! 0.源码地址
1.文件结构既然用 webpack 来编译源代码,那么很自然的我们的文件结构首先要分为 src/ 和 dist/,用开发者工具打开的应该是 dist/ 目录。 1.1.src/ 中文件结构大概长这样:. ├── app │ ├── app.js │ ├── app.json │ └── app.scss ├── assets │ └── vue-logo.png ├── comps │ └── todo │ ├── todo.js │ ├── todo.json │ ├── todo.less │ └── todo.wxml ├── pages │ └── index │ ├── index.js │ ├── index.json │ ├── index.less │ └── index.wxml ├── scripts │ ├── const │ │ ├── README.md │ │ └── index.js │ └── utils │ ├── README.md │ ├── event.js │ ├── format.js │ ├── index.js │ └── log.js ├── styles │ ├── global.styl │ ├── todomvc-app-css.css │ └── todomvc-common-base.css └── templates └── info.wxml
1.2.dist/ 中文件结构大概长这样:. ├── app.js ├── app.js.map ├── app.json ├── app.wxss ├── assets │ └── vue-logo.png ├── chunks │ ├── runtime.js │ ├── runtime.js.map │ ├── scripts.js │ ├── scripts.js.map │ ├── vendors.js │ └── vendors.js.map ├── comps │ └── todo │ ├── todo.js │ ├── todo.js.map │ ├── todo.json │ ├── todo.wxml │ └── todo.wxss ├── pages │ └── index │ ├── index.js │ ├── index.js.map │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── project.config.json └── templates └── info.wxml
1.3.整个项目文件结构大概长这样:. ├── README.md ├── dist/ ├── package.json ├── project.config.json ├── src/ ├── webpack.config.babel.js └── yarn.lock
2.webpack 基础配置2.1.entry/output小程序场景下的配置应该是多入口,主要分为 app、pages、comps 这三类。
在输出 output 部分有个坑:因为小程序使用的是 global,所以必须添加配置 output.globalObject 为 global。 不然... thirdScriptError VM937:1 sdk uncaught third Error Cannot read property 'webpackJsonp' of undefined TypeError: Cannot read property 'webpackJsonp' of undefined at http://127.0.0.1:40247/appservice/chunks/runtime.js:34:51 at http://127.0.0.1:40247/appservice/chunks/runtime.js:38:2 at require (http://127.0.0.1:40247/appservice/__dev__/WAService.js:19:7859) at http://127.0.0.1:40247/appservice/__dev__/WAService.js:19:7573 at http://127.0.0.1:40247/appservice/app.js:3:1 at require (http://127.0.0.1:40247/appservice/__dev__/WAService.js:19:7859) at http://127.0.0.1:40247/appservice/appservice?t=1527755092895:1020:9 // runtime var a = window.webpackJsonp = window.webpackJsonp || [] 详情可参阅这个 pr ps 在 mpvue 中似乎是通过修改 target 实现的... http://mpvue.com/build/mpvue-webpack-target/ 2.2.CommonChunk在 webpack 4 中有一个 breaking change,ref="https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366">即使用 SplitChunksPlugin 替换了之前很常用的 CommonsChunkPlugin 主要提取了三部分的公共代码:
现在又碰到个新的问题:如何引入这些 chunks? 在前端项目中一般我们通过 HtmlWebpackPlugin 插件在 html 文件中添加 <script> 标签引入,然鹅小程序中并没有 html 文件... 计将安出? 总不能每次都手动去 dist/app.js 中 require 这些文件吧? 这时候就要介绍另一款插件了~:BannerPlugin。 这个插件本来是用在文件头部添加 banner 的,但是也支持插入代码,因此利用这款插件我们就可以将这些公共依赖在 app.js 中统一引入一次即可。 TODO: 现版本的小程序提供了分包加载能力,因此这里还有优化空间 2.3.CopyWebpackPlugin顾名思义,这款插件的用处就是拷贝,利用这款插件我们就可以实现:
在使用时有一个知识点可以减少代码量:即 context 选项,这样就不用写 n 个 src/了... new CopyWebpackPlugin(copyCfgArr, { context: resolve('src'), }), 2.4.预处理器和 CSS 的处理这部分其实都是常规操作和一般 web 开发没啥区别,配置好对应的 loader 即可。 需要注意的点就是一定要使用 ExtractTextWebpackPlugin 插件来生成 .wxss 文件。 new ExtractTextPlugin('[name].wxss') 3.webpack + vue-loader这部分谈谈如何利用 vue-loader 实现在小程序中引用单文件组件(.vue)。 先看看 src/ 下的文件结构: . ├── app │ ├── App.vue │ ├── app.js │ └── app.json ├── assets │ └── vue-logo.png ├── comps │ ├── filter │ │ ├── Filter.vue │ │ └── index.js │ └── todo │ ├── Todo.vue │ └── index.js ├── pages │ ├── index │ │ ├── Index.vue │ │ └── index.js │ └── todos │ ├── Todos.vue │ └── index.js ├── scripts │ ├── const │ │ ├── README.md │ │ └── index.js │ └── utils │ ├── README.md │ ├── event.js │ ├── format.js │ ├── index.js │ └── log.js ├── styles │ ├── global.styl │ ├── todomvc-app-css.css │ └── todomvc-common-base.css └── templates └── info.wxml 其实已经和一般的 web 项目很相似了~ 3.1.vue-loader v15?随着 webpack 升级到了 v4,官方与之配合的 vue-loader 也升级到了 v15。 现在 Vue Loader 15 使用了一个不一样的策略来推导语言块使用的 loader。 简单来说就是咱们之前配置过的各个预处理器规则会被 vue-loader 自动使用。 因此我们只需要简单地添加一条规则即可读取 .vue 文件: { test: /\.vue$/, exclude: /node_modules/, loader: 'vue-loader', options: { compiler: { // mock vue-template-compiler compile: () => ({ staticRenderFns: [], }) }, }, }, options.compiler 是啥? 3.2.options.compileroptions.compiler 覆写用来编译单文件组件中 <template> 块的默认编译器。 在实际使用单文件组件时,我们通过 <template lang="wxml"> 来包裹原本的 .wxml 文件中的内容。 因为最终要编译成 .wxml 文件才能被开发者工具识别,所以我们还编写了一条规则通过 file-loader 生成最终的 .wxml 文件: { // 处理 <template lang="wxml">{...}</template> // 生成 .wxml 文件 test: /\.wxml$/, use: { loader: 'file-loader', options: { name: getNameByFilePathAndExt('.wxml'), }, }, }, |