欢迎来个人博客阅读:「原汁原味的配方:「微信小程序支持 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 的依赖有一个全局的把握。