歡迎來個人博客閱讀:「原汁原味的配方:「微信小程序支持 NPM」」javascript
微信小程序自己不支持 npm 包的使用,目前市面上不少框架也有了相對應的解決方案。java
本文旨在爲那些不肯意引入第三方框架, 想在小程序環境中寫原汁原味代碼的人(例如我),提供一種解決問題的思路。node
在現代的 Web 開發中,咱們對 Webpack 已經再熟悉不過了,簡單理解,它就是項目發佈以前,把全部資源都打包好,而後提供一個入口文件,在入口模板中引入這個入口文件。webpack
那麼個人思路,就是利用 Webpack 把咱們全部的 npm 依賴打包好,提供一個入口文件,在小程序開發中,咱們經過這個入口文件,進而使用 npm 的依賴。git
咱們最終實現的效果應該是這樣的。github
例如咱們小程序的首頁中,須要使用到 moment
web
pages/home/home.js:npm
const { moment } require('../npm/index'); const time = moment(); 複製代碼
webpack 默認輸出的 bundle.js
,是一個當即執行的閉包,如如下:gulp
使用 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"
官方解釋:
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 依賴了。 在這個基礎上,咱們就能夠打造一個使用 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 包的內容了。
若是你的項目中使用了構建工具的話,就能夠把「 webpack 打包 npm」 的這項任務加入到你的構建流程中。
我是使用 gulp 來作項目構建工做的,下面提供一種基於 gulp 的實現做爲參考。
工程目錄:
.
├── dist
│ ├── npm
│ │ └── index.js
│ └── pages
│ └── home
│ └── home.js
├── gulpfile.js
└── src
├── npm
│ └── index.js
└── pages
└── home
└── home.js
複製代碼
而 gulpfile 負責兩件事:
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')); }); // 開發模式命令 gulp.task('build', ['clean'], () => runSequence('scripts', 'npm')); 複製代碼
示例代碼:https://github.com/JerryC8080/use-npm-in-weapp/tree/master/step4
微信限制了項目的代碼量爲 2M,就算使用了分包機制,最多也是 4M 的代碼量。 區區一個 moment 庫的話,就算壓縮過,也須要兩百多 KB,這對於咱們的代碼量,是很不友好的。 咱們須要對 npm 的引入持很是謹慎的態度,去度量每一個依賴包的大小,想盡各類辦法減小依賴的代碼量。 譬如moment
咱們可使用 moment-mini
來代替,後者壓縮事後只須要 51KB。
並且我認爲把 npm 的依賴放在一個入口文件中,會讓咱們能夠對 npm 的依賴有一個全局的把握。