使用 babel 时需要 require js 吗?
你可能需要一些模块加载器,但这不是必需的。你有几个选择。以下内容将帮助您入门。
Rollup 是下一代 JavaScript 模块捆绑器。它原生地理解 ES2015 模块,并将生成一个不需要任何模块加载器来操作的包。未使用的导出将从输出中删除,这称为 tree-shaking。
现在我个人推荐使用 rollupjs,因为它产生最清晰的输出,并且易于设置,但是,它给出了不同的答案。所有其他方法都执行以下操作:
- 用 babel 编译 ES6 代码,使用你选择的模块格式
- 将已编译的模块与模块加载器连接起来,或者使用一个为您遍历依赖项的捆绑器。
对于 rollupjs,事情并不能真正以这种方式工作。在这里,rollup 是第一步,而不是 babel。默认情况下它只理解 ES6 模块。您必须提供一个入口模块,其中的依赖项将被遍历和连接。由于 ES6 允许在一个模块中使用多个命名导出,因此 rollupjs 足够聪明,可以去除未使用的导出,从而缩小包大小。不幸的是 rollupjs-s 解析器不理解 >ES6 语法,所以 ES7 模块必须在 rollup 解析它们之前编译,但编译不应该影响 ES6 导入。这是通过使用rollup-plugin-babel 插件和babel-preset-es2015-rollup 预设来完成的(这个预设与es2015 相同,除了模块转换器和external-helpers 插件)。因此,如果设置正确,汇总将对您的模块执行以下操作:
- 从文件系统中读取 ES6-7 模块
- 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 的.bundle 将包含一个不错的CommonJS 小加载器,并将您的转译模块组织成函数。您甚至可以进行相对导入。
示例:
// 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 模块转换器(在 babel 6 中称为 babel-plugin-transform-es2015-modules-amd)。之后将您编译的源代码与 WebPack 捆绑在一起。
WebPack 2 出来了! 它理解原生 ES6 模块,and will perform (or rather simulate) tree shaking 使用 babili-s 内置的死代码消除。目前(2016 年 9 月)我仍然建议使用带有 babel 的汇总,尽管我的意见可能会随着 WebPack 2 的第一个版本而改变。请随时在 cmets 中讨论您的意见。
自定义编译管道
有时您希望更好地控制编译过程。您可以像这样实现自己的管道:
首先,您必须配置 babel 以使用 amd 模块。默认情况下,babel 会转译为 CommonJS 模块,这在浏览器中处理起来有点复杂,尽管 browserify 设法以一种很好的方式处理它们。
- Babel 5:使用
{ modules: 'amdStrict', ... } 选项
- Babel 6:使用
es2015-modules-amd 插件
别忘了打开moduleIds: true 选项。
检查生成的模块名称的转译代码,定义的模块和所需的模块之间经常不匹配。见sourceRoot and moduleRoot。
最后,你必须有某种模块加载器,但这不是必需的 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 和已编译的模块连接在一起,并在其上运行 uglify。
Babel 的样板代码在每个模块中都是重复的
默认情况下,上面的大多数方法都是用 babel 单独编译每个模块,然后将它们连接在一起。这也是 babelify 所做的。但是如果你看一下编译后的代码,你会发现 babel 在每个文件的开头插入了大量的样板,其中大部分在所有文件中都是重复的。
为了防止这种情况,您可以使用babel-plugin-transform-runtime 插件。