使用 babel 时是否需要 require js?
你可能需要一些module加载器,但它不是必需的 RequireJS。您有多种选择。以下内容将帮助您入门。
Rollup 是下一代 JavaScript module打包器。它本机理解 ES2015 module,并将生成一个不需要任何module加载器来操作的包。未使用的导出将从输出中修剪,这称为摇树。
现在我个人推荐使用 rollupjs,因为它产生最清晰的输出,并且易于设置,但是,它给出了不同的答案。所有其他方法执行以下操作:
- 用 babel 编译 ES6 代码,使用你选择的module格式
- 将编译后的module与module加载器连接在一起,或者使用一个打包器来为你遍历依赖项。
使用 rollupjs 事情并没有真正以这种方式工作。在这里, rollup 是第一步,而不是 babel。它默认只理解 ES6 module。您必须提供一个入口module,其中的依赖项将被遍历和连接。由于 ES6 允许在一个module中存在多个命名导出,因此 rollupjs 足够智能,可以去除未使用的导出,从而缩小包的大小。不幸的是,rollupjs-s 解析器不理解 >ES6 语法,所以 ES7 module必须在 rollup 解析它们之前编译,但编译不应该影响 ES6 导入。它是通过使用rollup-plugin-babel
带有babel-preset-es2015-rollup
预设的插件来完成的(这个预设与 es2015 相同,除了module转换器和外部助手插件)。因此,如果正确设置,汇总将对您的module执行以下操作:
- 从文件系统中读取 ES6-7 module
- babel 插件在内存中编译成 ES6
- rollup 解析导入导出的 ES6 代码(使用 acorn 解析器,编译成 rollup)
- 它遍历整个图,并创建一个包(它仍然可能具有外部依赖关系,并且可能以您选择的格式导出条目的导出)
示例 nodejs 构建:
// setup by `npm i rollup rollup-plugin-babel babel-preset-es2015 babel-plugin-external-helpers --save-dev`
// build.js:
require("rollup").rollup({
entry: "./src/main.js",
plugins: [
require("rollup-plugin-babel")({
"presets": [["es2015", { "modules": false }]],
"plugins": ["external-helpers"]
})
]
}).then(bundle => {
var result = bundle.generate({
// output format - 'amd', 'cjs', 'es6', 'iife', 'umd'
format: 'iife'
});
require("fs").writeFileSync("./dist/bundle.js", result.code);
// sourceMaps are supported too!
}).then(null, err => console.error(err));
// setup by `npm i grunt grunt-rollup rollup-plugin-babel babel-preset-es2015 babel-plugin-external-helpers --save-dev`
// gruntfile.js
module.exports = function(grunt) {
grunt.loadNpmTasks("grunt-rollup");
grunt.initConfig({
"rollup": {
"options": {
"format": "iife",
"plugins": [
require("rollup-plugin-babel")({
"presets": [["es2015", { "modules": false }]],
"plugins": ["external-helpers"]
})
]
},
"dist": {
"files": {
"./dist/bundle.js": ["./src/main.js"]
}
}
}
});
}
// setup by `npm i gulp gulp-rollup rollup-plugin-babel babel-preset-es2015 babel-plugin-external-helpers --save-dev`
// gulpfile.js
var gulp = require('gulp'),
rollup = require('gulp-rollup');
gulp.task('bundle', function() {
gulp.src('./src/**/*.js')
// transform the files here.
.pipe(rollup({
// any option supported by Rollup can be set here.
"format": "iife",
"plugins": [
require("rollup-plugin-babel")({
"presets": [["es2015", { "modules": false }]],
"plugins": ["external-helpers"]
})
],
entry: './src/main.js'
}))
.pipe(gulp.dest('./dist'));
});
Babel 有一个简洁的包叫做babelify。它的用法简单明了:
$ npm install --save-dev babelify babel-preset-es2015 babel-preset-react
$ npm install -g browserify
$ browserify src/script.js -o bundle.js \
-t [ babelify --presets [ es2015 react ] ]
或者你可以从 node.js 使用它:
$ npm install --save-dev browserify babelify babel-preset-es2015 babel-preset-react
...
var fs = require("fs");
var browserify = require("browserify");
browserify(["./src/script.js"])
.transform("babelify", {presets: ["es2015", "react"]})
.bundle()
.pipe(fs.createWriteStream("bundle.js"));
这将立即转换和连接您的代码。Browserify's.bundle
将包含一个漂亮的小 CommonJS 加载器,并将您的转换module组织成函数。你甚至可以有相对的进口。
例子:
// project structure
.
+-- src/
| +-- library/
| | \-- ModuleA.js
| +-- config.js
| \-- script.js
+-- dist/
\-- build.js
...
// build.js
var fs = require("fs");
var browserify = require("browserify");
browserify(["./src/script.js"])
.transform("babelify", {presets: ["es2015", "react"]})
.bundle()
.pipe(fs.createWriteStream("dist/bundle.js"));
// config.js
export default "Some config";
// ModuleA.js
import config from '../config';
export default "Some nice export: " + config;
// script.js
import ModuleA from './library/ModuleA';
console.log(ModuleA);
要编译只需node build.js
在您的项目根目录中运行。
使用 babel 编译所有代码。我建议您使用 amd module转换器(babel-plugin-transform-es2015-modules-amd
在 babel 6 中调用)。之后,将您编译的源代码与 WebPack 捆绑在一起。
WebPack 2 出来了!它理解原生 ES6 module,并将使用babili -s 内置死代码消除来执行(或更确切地说是模拟)树摇动。目前(2016 年 9 月)我仍然建议使用 rollup 和 babel,尽管我的观点可能会随着 WebPack 2 的第一个版本而改变。请随时在评论中讨论您的意见。
自定义编译管道
有时您希望对编译过程有更多的控制。您可以像这样实现自己的管道:
首先,您必须配置 babel 以使用 amd module。默认情况下 babel 转译为 CommonJS module,这在浏览器中处理有点复杂,尽管 browserify 设法以一种很好的方式处理它们。
- Babel 5:使用
{ modules: 'amdStrict', ... }
选项
- Babel 6:使用
es2015-modules-amd
插件
不要忘记打开该moduleIds: true
选项。
检查生成的module名称的转译代码,定义的module和所需的module之间经常不匹配。请参阅sourceRoot 和 moduleRoot。
最后,您必须有某种module加载器,但这不是必需的 requirejs。有almondjs,一个运行良好的小需求垫片。您甚至可以实现自己的:
var __modules = new Map();
function define(name, deps, factory) {
__modules.set(name, { n: name, d: deps, e: null, f: factory });
}
function require(name) {
const module = __modules.get(name);
if (!module.e) {
module.e = {};
module.f.apply(null, module.d.map(req));
}
return module.e;
function req(name) {
return name === 'exports' ? module.e : require(name);
}
}
最后,您可以将加载器 shim 和已编译的module连接在一起,并在其上运行 uglify。
Babel 的样板代码在每个module中都是重复的
默认情况下,上述大多数方法都会单独使用 babel 编译每个module,然后将它们连接在一起。这也是 babelify 所做的。但是如果你查看编译后的代码,你会发现 babel 在每个文件的开头插入了很多样板,其中大部分在所有文件中都是重复的。
为了防止这种情况,您可以使用babel-plugin-transform-runtime
插件。