开门见山地说,小程序在日常开发中使用原生框架来开发还是挺不方便的,比如:
不支持 npm 包
不支持各种 CSS 预编译器
不支持配置 Babel 来转换一些 JavaScript 新特性
这样一来和日常开发前端页面的体验相比来说,简直就像在刀耕火种。
那么为了解决这些问题,我们能不能将前端开发中常用的 webpack 移植到小程序开发中呢?
当然可以!
0.源码地址在 webpack-simple 中文件结构和小程序相似。
而在 webpack-vue 中还增加了 vue-loader,因此你甚至还能利用 .vue 文件编写单文件组件。
注:已封装到 https://tuateam.github.io/tua... 中...1.文件结构
既然用 webpack 来编译源代码,那么很自然的我们的文件结构首先要分为 src/ 和 dist/,开发者工具的目标应该是 dist/ 目录。
注:开发者工具打开的应该是根目录,这样可以保存各种设置,可以在 project.config.json 中配置 "miniprogramRoot": "./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 └── 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 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-...2.2.CommonChunk
在 webpack 4 中有一个 breaking change,即使用 SplitChunksPlugin 替换了之前很常用的 CommonsChunkPlugin
主要提取了三部分的公共代码:
runtime: 是 webapck 在运行时连接各个模块的代码
vendors: 是提取的 node_modules 下的依赖
scripts: 是提取的 src/scripts/ 下的依赖
现在又碰到个新的问题:如何引入这些 chunks?
在前端项目中一般我们通过 HtmlWebpackPlugin 插件在 html 文件中添加 标签引入,然鹅小程序中并没有 html 文件...
计将安出?
总不能每次都手动去 dist/app.js 中 require 这些文件吧?
这时候就要介绍另一款插件了~:BannerPlugin。
这个插件本来是用在文件头部添加 banner 的,但是也支持插入代码,因此利用这款插件我们就可以将这些公共依赖在 app.js 中统一引入一次即可。
TODO: 现版本的小程序提供了分包加载能力,因此这里还有优化空间2.3.CopyWebpackPlugin
顾名思义,这款插件的用处就是拷贝,利用这款插件我们就可以实现:
复制 *.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")
注:已换成 mini-css-extract-plugin3.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 中, 会完成把它当作一个真实的 *.less 文件来加载。因此,为了这样处理它,你需要在你的主 webpack 配置中显式地提供一条规则。
简单来说就是咱们之前配置过的各个预处理器规则会被 vue-loader 自动使用。
因此我们只需要简单地添加一条规则即可读取 .vue 文件:
{ test: /.vue$/, exclude: /node_modules/, loader: "vue-loader", options: { compiler: { // mock vue-template-compiler compile: () => ({ staticRenderFns: [], }) }, }, },
options.compiler 是啥?
注意:随着 vue-loader 的升级,这部分的 mock 有变化...
options: { // mock vue-template-compiler compile: () => ({ staticRenderFns: [], }), parseComponent: require("vue-template-compiler") .parseComponent, }, },3.2.options.compiler
options.compiler 覆写用来编译单文件组件中 块的默认编译器。
在实际使用单文件组件时,我们通过 来包裹原本的 .wxml 文件中的内容。
因为最终要编译成 .wxml 文件才能被开发者工具识别,所以我们还编写了一条规则通过 file-loader 生成最终的 .wxml 文件:
{ // 处理 {...} // 生成 .wxml 文件 test: /.wxml$/, use: { loader: "file-loader", options: { name: getNameByFilePathAndExt(".wxml"), }, }, },
但是因为 vue-loader 默认会编译 template 中的内容将其生成一个个 render 函数。但其实在小程序场景中我们并不需要这一步骤。我们只想安安静静地将这些代码通过 file-loader 生成 .wxml 文件...
幸好 vue-loader 还提供了 options.compiler 这个参数用来传递自己的编译器。所以这里其实是 mock 了一下 vue-template-compiler。
3.3.Custom Blocks最后还有个问题没有解决:如何处理 .json 文件?
在其他的小程序框架中是这样处理的:
在 wepy 中将其作为组件的 config 属性
export default class Index extends wepy.page { //页面配置 config = { "navigationBarTitleText": "test" }; // ... }
在 mpvue 中是写在 main.js 的输出部分
// main.js export default { // 这个字段走 app.json config: { // 页面前带有 ^ 符号的,会被编译成首页,其他页面可以选填,我们会自动把 webpack entry 里面的入口页面加进去 pages: ["pages/logs/main", "^pages/index/main"], window: { backgroundTextStyle: "light", navigationBarBackgroundColor: "#fff", navigationBarTitleText: "WeChat", navigationBarTextStyle: "black" } } } // src/pages/logs/main.js export default { config: { navigationBarTitleText: "查看启动日志" } }
在 tua-mp 中目前采用的是自定义块的方式来实现的,即在 .vue 文件中新增了一个
{ "navigationBarTitleText": "查看启动日志" } ...
但是并没有将 app.json 的内容放到 App.vue 中,因为有时需要读取这里的页面配置。如果写到
例如为了实现从分享后的页面后退返回首页这个功能,在辅助函数中就需要读取页面和 tabBar 配置,生成分享链接(实际分享地址是首页,然后从首页再导航到被分享的页面)。
因此最优解是页面配置写在
TODO: 实现 mpvue 的方式处理 app.json
具体的配置如下:
{ // 处理4.总结{...} 代码块 // 生成 .json 文件 resourceQuery: /blockType=config/, use: { loader: "file-loader", options: { name: getNameByFilePathAndExt(".json"), }, }, },
综上,咱们在 webpack v4 和 vue-loader v15 的帮助下,让小程序拥有了以下能力:
加载 npm 包
提取 CommonChunk 减少打包体积
babel 编译 JavaScript 代码
支持 less/sass/stylus 等预处理器
单文件组件
不过话又说回来了...原生的小程序...又不是不能用~
注:这句话是黄章说的,Teacher Luo 没说过这话哟~
以上 to be continued...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/96869.html
摘要:假如图片链接有问题比如,依然展示占位图。使用单文件组件将配置模板脚本样式写在一个文件中,方便维护。 零、问题的由来 一般在前端展示图片时都会碰到这两个常见的需求: 图片未加载完成时先展示占位图,等到图片加载完毕后再展示实际的图片。 假如图片链接有问题(比如 404),依然展示占位图。甚至你还可以增加点击图片再次加载的功能。(例如知乎) 然鹅,小程序原生组件 image 并没有提供这...
摘要:而小程序官方的是在中调用方法来改变数据,从而改变界面。为了写测试让咱们来重构一把,利用学习过的函数式编程中的高阶函数把依赖注入。也就是说当中的某个数据更新的时候,我们并不知道它会影响哪个中的属性,特别的还有依赖于的情况。 众所周知 Vue 是借助 ES5 的 Object.defineProperty 方法设置 getter、setter 达到数据驱动界面,当然其中还有模板编译等等其他...
摘要:前言微信小程序中可以直接运行页面,这一新组件的产生,可能直接导致小程序数量迎来一波高峰。微信小程序配置系列问题配置域名业务域名中配置的就是小程序以及和中引用的域名。 今日励志语 要接受自己行动所带来的责任而非自己成就所带来的荣耀。 前言 微信小程序中可以直接运行 web 页面,这一新组件 web-view 的产生,可能直接导致小程序数量迎来一波高峰。本篇博文将从业务选型,微信小程序后台...
项目需求简单描述 用户长按录音,松手后直接结束录音,结束录音后,用户可以选择重新录音、播放刚才的录音,上传录音(这里的上传录音指上传到自己服务器,上传步骤是,前端调用wx.uploadVoice,后台再到微信服务器下载音频文件,上传到自己的服务器)。注意,音频文件自上传时间算起在微信服务器的有效期为3天。由于后台从微信服务器下载的音频文件是amr格式的,需要后台先把amr文件转换成MP3,前端用a...
阅读 623·2023-04-25 15:49
阅读 3078·2021-09-22 15:13
阅读 1084·2021-09-07 10:13
阅读 3445·2019-08-29 18:34
阅读 2538·2019-08-29 15:22
阅读 478·2019-08-27 10:52
阅读 641·2019-08-26 18:27
阅读 2972·2019-08-26 13:44