前言
剛入門微信小程序的時候,一切都基於微信web開發者工具,沒有使用其他框架,也沒有工程化的概念。當時做的項目都比較簡單,單單用微信web開發者工具倒也得心應手。學了些東西后,就按捺不住地想跳出原生工具的條條框框,把近些日子學的東西都拿出來熬一熬。
已有的一個小程序項目使用了github上一個使用webpack、babel、sass開發的小程序腳手架(wxapp-boilerplate),我需要在不變動原有項目代碼的基礎上,使用gulp來重構項目的工作流。
使用體驗:使用vscode配合各種插件在src目錄下開發,使用微信web開發者工具預覽調試,通過cmd打開服務,可以用gulp命令快速創建page、component模板。還是很nice的。
介紹
根據開發中的剛需和痛點,最終做了以下工作,有實現不到位的,歡迎大家提出建議。
sass編譯成wxss,同時處理了@import直接導入導致單文件過大的問題
修改gulpfile.js的aliasWords可為項目js配置alias
支持在src中的wxs使用es6+
使用微信web開發者工具的Npm構建
gulp命令快速創建page、component模板
項目地址:https://github.com/bluehat999/weapp-gulp
文章地址:https://www.cnblogs.com/mthz/p/weapp-gulp.html
要點
實現過程中遇到的問題,也是一些要點:
1.項目中的WXS文件使用了ES6語法,而WXS原生不支持ES6
wxs不支持ES6 語法,其標准基本是參考ES5 標准.
解決方案是使用babel將wxs像js那樣從ES6轉為ES5,在使用babel的時候,有個模塊始終無法加載到,查出問題應該是babel的依賴間版本不一致的問題,就在github上查了gulp-babel的倉庫,參照readme.md的示例重新安裝模塊和使用,就成功解決。
安裝:
npm install --save-dev gulp-babel @babel/core @babel/preset-env
使用:
const f_wxs = done => {
return gulp.src(WXS, { since: gulp.lastRun(f_wxs) })
.pipe(plumber({ errorHandler: onError }))
.pipe(babel({
presets: ['@babel/preset-env']
}))
.pipe(rename({extname:'.wxs'}))
.pipe(gulp.dest(DIST))
}
gulp.task('wxs', f_wxs)
2.sass編譯成wxss,解決@import導致文件體積過大的問題
css不支持import語法,sass在處理@import時會直接把對應文件添加過來,從而導致wxss文件體積過大。
而wxss支持import語法,同時限制了單包代碼不超過2M,所以需要采用方法避免sass編譯時直接導入樣式,而是沿用@import。簡單來說,就是讓sass編譯時不處理import語句。
可以改sass的源碼,讓它跳過import,也可以在交給sass編譯前將文件中的import語句注釋掉,編譯結束后再取消注釋。
但是不處理import語句也會帶來一個問題:文件中使用了引入文件中的變量和mixin時,會由於沒有引入而找不到變量和mixin。我們需要再給不處理import語句加一個判斷條件。
一般項目都會將全局的(需要被引用的)變量和mixin放在單獨的文件里,而且會適當分成多個,以免單個文件過大。將這些文件放在指定的目錄里,將目錄路徑作為判斷條件來過濾掉需要import的變量和mixin的sass文件。
const SRC = './src/**/'
const SASS = [`${SRC}*.{scss,wxss,scss}`]
const DIRECTIMPORT = [`styles`, `font`]
const f_sass = done => {
return gulp.src([...SASS,...DIRECTIMPORT.map(item => `!${SRC}${item}/**/*`)],
{ since: gulp.lastRun(f_sass) ,allowEmpty:true})
.pipe(plumber({ errorHandler: onError }))
.pipe(tap((file) => {
const filePath = path.dirname(file.path);
file.contents = new Buffer(
String(file.contents)
.replace(/@import\s+['|"](.+)['|"];/g, ($1, $2) => {
const imPath = path.resolve(filePath + '/' + $2)
return DIRECTIMPORT.some( item => { return imPath.indexOf(item) > -1} ) ? $1 : `/** ${$1} **/`
})
)
}))
.pipe(sass())
.pipe(replace(/(\/\*\*\s{0,})(@.+)(\s{0,}\*\*\/)/g, ($1, $2, $3) => $3.replace(/\.scss/g, '.wxss')))
.pipe(rename({ extname: '.wxss' }))
.pipe(gulp.dest(DIST))
}
gulp.task('sass', f_sass)
3.微信小程序使用npm
小程序基礎庫2.2.1以上的版本開始支持npm安裝第三方包。官方文檔
仔細讀了文檔,和它的示例代碼,不過還是被坑了一會。
node_modules必須放在小程序根目錄或其子目錄下,npm的package.json也是,否則在微信web開發者工具對dist進行npm構建時會提示找不到npm。
它的npm構建會在代碼同級目錄生成source map文件,方便做逆向調試。
不過npm的命令是需要在dist目錄的上一級使用的,如果直接放在dist里,上一級就用不了,本來理想的方案是放在dist、修改npm尋找node_modules文件的地點,或者放在上一級、修改開發者工具構建時尋找node_modules文件的地點。
但是我實在沒查到如何修改,也許看源碼可以,所以采用了比較麻煩的方案。就是node_modules放在上一級,寫一個gulp task將它整體復制到dist。node_modules畢竟挺大的,復制一份要用去10幾秒,開銷挺大,不過也只有node_modules更新了需要同步一下,總的來說也還好。
4.使用gulp-tap獲取處理的文件名時並計算一個相對路徑
原有項目使用了webpack來管理文件依賴,改用gulp的話,原有的一些依賴路徑就是錯誤的,(比如引用config和utils目錄下的文件時),如果直接修改代碼,會和項目原有的編程習慣沖突,所以決定直接在gulp構建時來把錯誤的路徑改為正確的相對路徑。
5.微信小程序中使用lodash報錯
Uncaught TypeError: Cannot read property 'prototype' of undefined
找到一篇解釋的很好的文章
按照文章中給出的方案,在開發者工具中構建Npm后,可使用gulp lodash自動修改相應文件來修復這個問題。
6.微信小程序不支持async / await 語法
因為小程序支持ES6轉ES5,我就沒有在gulp中使用babel,沒考慮到小程序對ES6以上的特性不支持。
小程序報了上訴錯誤,我首先查了一下regeneratorRuntime is not defined的錯誤,大致得知是異步的錯誤,找到報錯的代碼,發現使用了async await,猜測是微信小程序不支持,需要引入相應的包,然后google到了比較好的答案。
從facebook代碼倉庫下載到了相應源碼(只需要runtime.js就可以了),放入utils中,在使用了async的地方引入。不過我又遇到了下面的問題:
源碼中報錯部位在catch中,文件中既沒有引入也沒有定義這個Function,在網上也找不到答案,考慮在catch中,應該是處理報錯之類的,注釋掉也影響不大,我就把它注釋掉了。
更多改進
改進一定會有的,如果覺得還行或者不行,勞煩關注一下我的博客和github。