開門見山地說,小程序在日常開發中使用原生框架來開發還是挺不方便的,比如:
不支持 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...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/96869.html
摘要:假如圖片鏈接有問題比如,依然展示占位圖。使用單文件組件將配置模板腳本樣式寫在一個文件中,方便維護。 零、問題的由來 一般在前端展示圖片時都會碰到這兩個常見的需求: 圖片未加載完成時先展示占位圖,等到圖片加載完畢后再展示實際的圖片。 假如圖片鏈接有問題(比如 404),依然展示占位圖。甚至你還可以增加點擊圖片再次加載的功能。(例如知乎) 然鵝,小程序原生組件 image 并沒有提供這...
摘要:而小程序官方的是在中調用方法來改變數據,從而改變界面。為了寫測試讓咱們來重構一把,利用學習過的函數式編程中的高階函數把依賴注入。也就是說當中的某個數據更新的時候,我們并不知道它會影響哪個中的屬性,特別的還有依賴于的情況。 眾所周知 Vue 是借助 ES5 的 Object.defineProperty 方法設置 getter、setter 達到數據驅動界面,當然其中還有模板編譯等等其他...
摘要:前言微信小程序中可以直接運行頁面,這一新組件的產生,可能直接導致小程序數量迎來一波高峰。微信小程序配置系列問題配置域名業務域名中配置的就是小程序以及和中引用的域名。 今日勵志語 要接受自己行動所帶來的責任而非自己成就所帶來的榮耀。 前言 微信小程序中可以直接運行 web 頁面,這一新組件 web-view 的產生,可能直接導致小程序數量迎來一波高峰。本篇博文將從業務選型,微信小程序后臺...
項目需求簡單描述 用戶長按錄音,松手后直接結束錄音,結束錄音后,用戶可以選擇重新錄音、播放剛才的錄音,上傳錄音(這里的上傳錄音指上傳到自己服務器,上傳步驟是,前端調用wx.uploadVoice,后臺再到微信服務器下載音頻文件,上傳到自己的服務器)。注意,音頻文件自上傳時間算起在微信服務器的有效期為3天。由于后臺從微信服務器下載的音頻文件是amr格式的,需要后臺先把amr文件轉換成MP3,前端用a...
閱讀 644·2023-04-25 15:49
閱讀 3099·2021-09-22 15:13
閱讀 1237·2021-09-07 10:13
閱讀 3467·2019-08-29 18:34
閱讀 2556·2019-08-29 15:22
閱讀 499·2019-08-27 10:52
閱讀 677·2019-08-26 18:27
閱讀 3009·2019-08-26 13:44