欢迎光临,了解微信小程序开发,就上易用通!

终极蛇皮上帝视角之微信小程序之告别“刀耕火种”

发布:2018-06-26 12:11浏览: 来源:网络 作者:cola

开门见山地说,小程序在日常开发中使用原生框架来开发还是挺不方便的,比如:

  • 不支持 npm 包
  • 不支持各种 CSS 预编译器
  • 不支持配置 Babel 来转换一些 JavaScript 新特性

这样一来和日常开发前端页面的体验相比来说,简直就像在刀耕火种。

那么为了解决这些问题,我们能不能将前端开发中常用的 webpack 移植到小程序开发中呢?

当然可以!

 

0.源码地址

终极蛇皮上帝视角之微信小程序之告别“刀耕火种”(图1)

  • 在 webpack-simple 中文件结构和小程序相似。
  • 而在 webpack-vue 中还增加了 vue-loader,因此你甚至还能利用 .vue 文件编写单文件组件。

终极蛇皮上帝视角之微信小程序之告别“刀耕火种”(图2)

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
  • app/: 应用入口
  • assets/: 资源文件,比如图片
  • comps/: 组件
  • pages/: 页面
  • scripts: 公用代码
  • scripts/const: 常量(已配置别名 @const)
  • scripts/utils: 辅助函数(已配置别名 @utils)
  • styles/: 公用样式
  • templates/: 模板

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
  • chunks/: 公共依赖
    • runtime: 是 webapck 在运行时连接各个模块的代码
    • vendors: 是提取的 node_modules 下的依赖
    • scripts: 是提取的 src/scripts/ 下的依赖

1.3.整个项目文件结构大概长这样:


.
├── README.md
├── dist/
├── package.json
├── project.config.json
├── src/
├── webpack.config.babel.js
└── yarn.lock
  • src/: 源码
  • dist/: 打包后代码

2.webpack 基础配置

2.1.entry/output

小程序场景下的配置应该是多入口,主要分为 app、pages、comps 这三类。

  • app: 将 src/app/ 下的文件编译成 dist/ 根目录下的 app.js/app.json/app.wxss
  • pages: src/pages/ -> dist/pages/
  • comps: src/comps/ -> dist/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 https://127.0.0.1:40247/appservice/chunks/runtime.js:34:51
    at https://127.0.0.1:40247/appservice/chunks/runtime.js:38:2
    at require (https://127.0.0.1:40247/appservice/__dev__/WAService.js:19:7859)
    at https://127.0.0.1:40247/appservice/__dev__/WAService.js:19:7573
    at https://127.0.0.1:40247/appservice/app.js:3:1
    at require (https://127.0.0.1:40247/appservice/__dev__/WAService.js:19:7859)
    at https://127.0.0.1:40247/appservice/appservice?t=1527755092895:1020:9


// runtime
var a = window.webpackJsonp = window.webpackJsonp || []

详情可参阅这个 pr

ps 在 mpvue 中似乎是通过修改 target 实现的... https://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

主要提取了三部分的公共代码:

  • runtime: 是 webapck 在运行时连接各个模块的代码
  • vendors: 是提取的 node_modules 下的依赖
  • scripts: 是提取的 src/scripts/ 下的依赖
现在又碰到个新的问题:如何引入这些 chunks?

在前端项目中一般我们通过 HtmlWebpackPlugin 插件在 html 文件中添加 <script> 标签引入,然鹅小程序中并没有 html 文件...

计将安出?

总不能每次都手动去 dist/app.js 中 require 这些文件吧?

这时候就要介绍另一款插件了~:BannerPlugin。

这个插件本来是用在文件头部添加 banner 的,但是也支持插入代码,因此利用这款插件我们就可以将这些公共依赖在 app.js 中统一引入一次即可。

TODO: 现版本的小程序提供了分包加载能力,因此这里还有优化空间

2.3.CopyWebpackPlugin

顾名思义,这款插件的用处就是拷贝,利用这款插件我们就可以实现:

  • 复制 project.config.json
  • 复制 *.json
  • 复制 *.wxml
  • 复制 *.wxss
  • 复制 assets/
  • 复制 templates/

在使用时有一个知识点可以减少代码量:即 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。
在 v15 中,<style lang="less"> 会完成把它当作一个真实的 *.less 文件来加载。因此,为了这样处理它,你需要在你的主 webpack 配置中显式地提供一条规则。

简单来说就是咱们之前配置过的各个预处理器规则会被 vue-loader 自动使用。

因此我们只需要简单地添加一条规则即可读取 .vue 文件:


{
    test: /\.vue$/,
    exclude: /node_modules/,
    loader: 'vue-loader',
    options: {
        compiler: {
            // mock vue-template-compiler
            compile: () => ({
                staticRenderFns: [],
            })
        },
    },
},
options.compiler 是啥?

3.2.options.compiler

options.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'),
        },
    },
},





免责声明:本站所有文章和图片均来自用户分享和网络收集,文章和图片版权归原作者及原出处所有,仅供学习与参考,请勿用于商业用途,如果损害了您的权利,请联系网站客服处理。