|
微(wei)信小程序(xu)本身不支持 npm 包的使用,目前市面上很多框(kuang)架也(ye)有了相(xiang)對(dui)應的解決(jue)方案。 本(ben)文(wen)旨在為那些不愿意引入第三方框架, 想(xiang)在小程序環(huan)境中寫原(yuan)汁原(yuan)味(wei)代碼的(de)人(ren)(例如我),提供一種(zhong)解決問題的(de)思路。 在現代(dai)的 Web 開發中,我們對(dui) Webpack 已經(jing)再熟悉不過了,簡單理解,它就是(shi)項目發布之前,把所有資(zi)源都打(da)包好(hao),然后提(ti)供一個(ge)入(ru)口(kou)文(wen)件(jian),在入(ru)口(kou)模板中引入(ru)這個(ge)入(ru)口(kou)文(wen)件(jian)。 那(nei)么我的思路,就是(shi)利用(yong) Webpack 把(ba)我們(men)所有的 npm 依(yi)(yi)賴打(da)包好,提供一(yi)個入口文件,在小程序開發中(zhong),我們(men)通過這個入口文件,進而使用(yong) npm 的依(yi)(yi)賴。
我們最終(zhong)實現的(de)效果應(ying)該(gai)是這樣的(de)。 例如我(wo)們(men)小程序的首頁中,需要使用到 moment pages/home/home.js:
const { moment } require('../npm/index');
const time = moment();
Webpack 打包 npm 依賴webpack 默(mo)認輸出的 bundle.js ,是(shi)一(yi)個立即執(zhi)行(xing)的閉包(bao),如以下: 使用 webpack.config.js 配(pei)置(zhi):
const path = require('path');
module.exports = {
entry: './foo.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};
運行 $ webpack 生成的 bundle.js :
(function(modules){
// webpackBootstrap
})([module1, module2, module3]);
示例代碼: //github.com/JerryC8080/use-npm-in-weapp/tree/master/step1 這(zhe)樣(yang)的(de)代碼,顯然沒法達到(dao)我們要(yao)的(de)效果。 幸好 webpack 提供了 output.libraryTarget 的配置項(xiang)。 output.libraryTarget: “commonjs2”對(dui)于 output.libraryTarget: "commonjs2" 官(guan)方解釋: The return value of your entry point will be assigned to the module.exports. 通過配置該屬性,我們能保證 webpack 打包(bao)出來的 bundle.js ,是模塊化的。 當(dang)然 output.libraryTarget 還有其他(ta)的選(xuan)項值,可以(yi)查(cha)閱 官方(fang)文(wen)檔 。 例如,使用 webpack.config.js 配置:
const path = require('path');
module.exports = {
entry: './foo.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
libraryTarget: 'commonjs2',
}
};
運(yun)行 $ webpack 生成的 bundle.js :
module.exports = (function(modules){
// webpackBootstrap
})([module1, module2, module3]);
示例(li)代(dai)碼(ma): //github.com/JerryC8080/use-npm-in-weapp/tree/master/step2 這樣,我們就可以通(tong)過 require('bundle.js') , 來使用 npm 依賴(lai)了。 在這個(ge)基礎上(shang),我們就可以打造一個(ge)使用 npm 依賴的(de)入口。 打造 npm 入口建立入口文(wen)件(jian):npm.js
const momennt = require('moment');
module.exports = {
momennt,
};
配置(zhi)文件:webpack.config.js
const path = require('path');
module.exports = {
entry: './entry.js',
output: {
path: path.resolve(__dirname, 'npm'),
filename: 'index.js'
},
};
運行 $ webpack ,輸出 ./npm/index.js 打包文件,對(dui)應的目(mu)錄: . ├── entry.js ├── npm │ └── index.js └── webpack.config.js 示(shi)例代碼(ma): //github.com/JerryC8080/use-npm-in-weapp/tree/master/step3 笨拙點的(de)方法,你只需(xu)要(yao)把 npm/index.js 拷貝(bei)到你的(de)項目(mu)中,就(jiu)可(ke)以(yi)使用你所(suo)引入的(de) npm 包的(de)內容了。 如果你(ni)的(de)(de)項目中使用了構建工具(ju)的(de)(de)話,就可以把「 webpack 打包 npm」 的(de)(de)這項任(ren)務加入到你(ni)的(de)(de)構建流程中。 我是使用(yong) gulp 來做項(xiang)目構建(jian)工(gong)作的,下面提供一(yi)種基于 gulp 的實現作為參(can)考。 結合 Gulp 做項目工程化工(gong)程目錄:
.
├── dist
│ ├── npm
│ │ └── index.js
│ └── pages
│ └── home
│ └── home.js
├── gulpfile.js
└── src
├── npm
│ └── index.js
└── pages
└── home
└── home.js
而 gulpfile 負責兩件(jian)事:
gulpfile.js:
const gulp = require('gulp');
const babel = require('gulp-babel');
const del = require('del');
const runSequence = require('run-sequence');
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
const webpackConfig = {
module: {
loaders: [{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: ['es2015'],
},
}],
},
output: {
filename: 'index.js',
libraryTarget: 'commonjs2',
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
],
};
// 清空 ./dist 目錄
gulp.task('clean', () => del(['./dist/**']));
// 打包 npm 依賴
gulp.task('npm', () => {
gulp.src('./src/npm/*.js')
.pipe(webpackStream(webpackConfig), webpack)
.pipe(gulp.dest('./dist/npm'));
});
// 編譯 JS 文件
gulp.task('scripts', () => {
gulp.src(['./src/**/*.js', '!./src/npm/*.js'])
.pipe(babel({
presets: ['stage-0', 'es2015'],
}))
.pipe(gulp.dest('./dist'));
});
// 開發模式命令
gulp.task('build', ['clean'], () => runSequence('scripts', 'npm'));
示例代碼: //github.com/JerryC8080/use-npm-in-weapp/tree/master/step4 關于控制 npm 文件代碼量微信限(xian)制了(le)項目的代碼量為 2M,就算使用了(le)分包(bao)機制,最(zui)多也是 4M 的代碼量。 區(qu)區(qu)一個(ge) moment 庫的(de)話,就算壓縮過,也需要兩(liang)百(bai)多 KB,這對于我們的(de)代(dai)碼量,是很不(bu)友(you)好的(de)。 我們需要對 npm 的(de)引(yin)入(ru)持(chi)非常謹慎的(de)態度,去(qu)度量每個依賴包的(de)大小,想盡各種辦(ban)法減少依賴的(de)代(dai)碼量。 譬如 moment 我們(men)可以使用(yong) moment-mini 來代替,后者(zhe)壓縮過后只需要 51KB。 而且(qie)我認為把 npm 的(de)依賴(lai)放在一(yi)個入口(kou)文件中,會讓(rang)我們可以對(dui) npm 的(de)依賴(lai)有一(yi)個全局的(de)把握。 |