歡迎來我的博客閱讀:「原汁原味的配方:「微信小程序支持 NPM」」
微信小程序本身不支持 npm 包的使用,目前市面上很多框架也有了相對應的解決方案累铅。
本文旨在為那些不愿意引入第三方框架糕非, 想在小程序環(huán)境中寫原汁原味代碼的人(例如我)蒙具,提供一種解決問題的思路。
在現(xiàn)代的 Web 開發(fā)中朽肥,我們對 Webpack 已經(jīng)再熟悉不過了禁筏,簡單理解,它就是項目發(fā)布之前衡招,把所有資源都打包好篱昔,然后提供一個入口文件,在入口模板中引入這個入口文件。
那么我的思路州刽,就是利用 Webpack 把我們所有的 npm 依賴打包好空执,提供一個入口文件,在小程序開發(fā)中穗椅,我們通過這個入口文件辨绊,進而使用 npm 的依賴。
我們最終實現(xiàn)的效果應該是這樣的房待。
例如我們小程序的首頁中邢羔,需要使用到 moment
pages/home/home.js:
const { moment } require('../npm/index');
const time = moment();
Webpack 打包 npm 依賴
webpack 默認輸出的 bundle.js
,是一個立即執(zhí)行的閉包桑孩,如以下:
使用 webpack.config.js 配置:
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]);
示例代碼:https://github.com/JerryC8080/use-npm-in-weapp/tree/master/step1
這樣的代碼拜鹤,顯然沒法達到我們要的效果。
幸好 webpack 提供了 output.libraryTarget
的配置項流椒。
output.libraryTarget: "commonjs2"
對于 output.libraryTarget: "commonjs2"
官方解釋:
The return value of your entry point will be assigned to the module.exports.
通過配置該屬性敏簿,我們能保證 webpack 打包出來的 bundle.js
,是模塊化的宣虾。
當然 output.libraryTarget
還有其他的選項值惯裕,可以查閱官方文檔。
例如绣硝,使用 webpack.config.js 配置:
const path = require('path');
module.exports = {
entry: './foo.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
libraryTarget: 'commonjs2',
}
};
運行 $ webpack
生成的 bundle.js
:
module.exports = (function(modules) {
// webpackBootstrap
})([module1, module2, module3]);
示例代碼:https://github.com/JerryC8080/use-npm-in-weapp/tree/master/step2
這樣蜻势,我們就可以通過 require('bundle.js')
, 來使用 npm 依賴了。
在這個基礎(chǔ)上鹉胖,我們就可以打造一個使用 npm 依賴的入口握玛。
打造 npm 入口
建立入口文件:npm.js
const momennt = require('moment');
module.exports = {
momennt,
};
配置文件: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
打包文件甫菠,對應的目錄:
.
├── entry.js
├── npm
│ └── index.js
└── webpack.config.js
示例代碼:https://github.com/JerryC8080/use-npm-in-weapp/tree/master/step3
笨拙點的方法挠铲,你只需要把 npm/index.js
拷貝到你的項目中,就可以使用你所引入的 npm 包的內(nèi)容了寂诱。
如果你的項目中使用了構(gòu)建工具的話拂苹,就可以把「 webpack 打包 npm」 的這項任務加入到你的構(gòu)建流程中。
我是使用 gulp 來做項目構(gòu)建工作的痰洒,下面提供一種基于 gulp 的實現(xiàn)作為參考瓢棒。
結(jié)合 Gulp 做項目工程化
工程目錄:
.
├── dist
│ ├── npm
│ │ └── index.js
│ └── pages
│ └── home
│ └── home.js
├── gulpfile.js
└── src
├── npm
│ └── index.js
└── pages
└── home
└── home.js
而 gulpfile 負責兩件事:
- 把 src 的 js 文件通過 babel 編譯到 dist 目錄(示例中忽略其他 wxml、wxss 文件)
- 把
npm/index.js
通過 webpack 打包到dist/npm/index.js
丘喻,并壓縮音羞。
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'));
});
// 開發(fā)模式命令
gulp.task('build', ['clean'], () => runSequence('scripts', 'npm'));
示例代碼:https://github.com/JerryC8080/use-npm-in-weapp/tree/master/step4
關(guān)于控制 npm 文件代碼量
微信限制了項目的代碼量為 2M,就算使用了分包機制仓犬,最多也是 4M 的代碼量嗅绰。
區(qū)區(qū)一個 moment 庫的話,就算壓縮過,也需要兩百多 KB窘面,這對于我們的代碼量翠语,是很不友好的。
我們需要對 npm 的引入持非常謹慎的態(tài)度财边,去度量每個依賴包的大小肌括,想盡各種辦法減少依賴的代碼量。
譬如moment
我們可以使用 moment-mini
來代替酣难,后者壓縮過后只需要 51KB谍夭。
而且我認為把 npm 的依賴放在一個入口文件中,會讓我們可以對 npm 的依賴有一個全局的把握憨募。