使用babel时需要使用js吗?


98

我正在试验ES6,然后我使用gulp进行构建并通过babel移植到ES5。输出未在节点中运行,只是通过标签从.htm文件链接到该节点。我想我需要补充

<script src='require.js'></script>

或类似的东西。

我正在尝试导入/导出。

////////////////scripts.js
import {Circle} from 'shapes';

c = new Circle(4);

console.log(c.area());


/////////////////shapes.js
export class Circle {

    circle(radius) {
        this.radius = radius;
    }

    area() {
        return this.radius * this.radius * Math.PI;
    } 

}

错误是

Uncaught ReferenceError: require is not defined

引用此(在gulp中的.pipe(babel())之后)

var _shapes = require('shapes');

3
是的,因为require浏览器中不存在,所以您需要使用某些构建工具,例如Require.js,Browserify或Webpack。
乔丹

1
啊,在我的Google搜索中添加了browserify,这给了我答案,谢谢。
杰森2015年

10
FWIW,请注意该错误消息并不表示您需要require.js。Babel默认将模块转换为CommonJS,这是Node所使用的,并定义了一个require函数(同样,与require.js无关)。但是,您可以告诉Babel将模块转换为其他东西,例如AMD或UMD,然后将其与require.js一起使用。无论哪种方式,都需要一个系统来在浏览器中加载模块,因为默认情况下浏览器尚未提供模块。
Felix Kling

Answers:


136

使用babel时需要使用js吗?

您可能需要一些模块加载器,但并不需要RequireJS。您有几种选择。以下内容将帮助您入门。


使用rollup-plugin-babel的rollup.js

汇总是下一代JavaScript模块捆绑程序。它本身就了解ES2015模块,并将产生不需要任何模块加载器即可运行的捆绑软件。未使用的出口将从输出中删除,这称为摇树。

现在,我个人建议使用rollupjs,因为它产生最清晰的输出,并且易于设置,但是,它为答案提供了不同的方面。所有其他方法都执行以下操作:

  1. 用babel编译ES6代码,使用您选择的模块格式
  2. 将编译的模块与模块加载器并置在一起,或使用将为您遍历依赖项的捆绑器。

使用rollupjs,事情并非真的能以这种方式工作。在这里,汇总是第一步,而不是babel。默认情况下,它仅了解ES6模块。您必须提供一个入口模块,其依赖关系将被遍历和连接。由于ES6在一个模块中允许多个命名的导出,因此rollupjs足够聪明,可以删除未使用的导出,从而缩小了包的大小。不幸的是,rollupjs-s解析器无法理解> ES6语法,因此必须在汇总之前解析ES7模块,但是编译不会影响ES6导入。这是通过使用rollup-plugin-babel具有babel-preset-es2015-rollup预设的插件来完成的(此预设与es2015相同,但模块转换器和外部助手插件除外)。因此,如果设置正确,汇总将对您的模块执行以下操作:

  1. 从文件系统读取ES6-7模块
  2. babel插件将其编译到内存中的ES6
  3. 汇总分析导入和导出的ES6代码(使用橡子分析器,编译为汇总)
  4. 它遍历整个图,并创建一个捆绑包(捆绑包可能仍然具有外部依赖性,并且条目的导出可能以您选择的格式导出)

示例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));

使用grunt-rollup构建示例grunt

// 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"]
        }
      }
    }
  });
}

使用gulp-rollup构建gulp的示例

// 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'));
});

Babelify + Browserify

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 + WebPack

使用babel编译所有代码。我建议您使用amd模块变压器(babel-plugin-transform-es2015-modules-amd在babel 6中调用)。之后,将已编译的源代码与WebPack捆绑在一起。

WebPack 2已经发布!它了解本机ES6模块,并将使用babili -s内置的死代码消除功能执行(或模拟)树摇。目前(2016年9月),我仍然建议使用babel进行汇总,尽管我的观点可能会随着WebPack 2的第一个发行版而改变。请随时在评论中讨论您的观点。


定制编译管道

有时您希望对编译过程有更多的控制。您可以像这样实现自己的管道:

首先,您必须将babel配置为使用amd模块。默认情况下,babel会转换为CommonJS模块,在浏览器中处理起来有点复杂,尽管browserify可以很好地处理它们。

  • 通天塔5:使用{ modules: 'amdStrict', ... }选项
  • Babel 6:使用es2015-modules-amd插件

不要忘记打开该moduleIds: true选项。

检查转码的生成模块名称,定义的模块和所需的模块之间经常不匹配。参见sourceRoot和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);
    }
}

最后,您可以将加载程序填充程序和已编译的模块连接在一起,并在其上运行uglify。


Babel的样板代码在每个模块中都有重复

默认情况下,上述大多数方法都使用babel分别编译每个模块,然后将它们串联在一起。这也是babelify所做的。但是,如果您看一下已编译的代码,就会发现babel在每个文件的开头插入了许多样板,其中大部分都是在所有文件中重复的。

为了防止这种情况,您可以使用babel-plugin-transform-runtime插件。


1
这太血腥了!谢谢。回复:每个文件都有重复的Babel样板-假设gzip会否定一切,这是否正确?
iono

1
我本人从未对其进行过度量,但是我假设有人会在分发之前缩小捆绑包,而缩小可能会为本地人找到不同的名称,因此它们不会完全相同。Gzip应该找到共同的部分(导致良好的压缩率),但是浏览器仍然必须单独解析它们。最终,这应该不会引起太大的开销,但是会有像我这样的人不喜欢重复的代码。
塔玛斯·赫格杜斯

足够公平,感谢您的回应。同样,在您必须在版本控制中备份或跟踪输出代码(未压缩的文件大小成倍增加)或出于任何原因希望输出最小化的情况下,这也可能很有意义。
iono

gulp-rollup可能也是该列表的一个很好的补充
GGG

@GGG添加了gulp示例。不幸的是,目前这些示例都无法在Windows上运行,请参见代码上方的说明。
塔玛斯·赫格杜斯

8

准系统webpack 2

1)如果这是您的根目录:

index.html

<html>
  ...
  <script src="./bundle.js"></script>
  ...
</html>

scripts.js

import { Circle } from './shapes.js';
  ...

Shapes.js

export class Circle {
  ...
}

2)有安装节点的节点

3)在您的终端中运行以下命令:

$ npm install -g webpack

5)在您的根目录中运行以下命令:

$ webpack scripts.js bundle.js

现在,您的根目录中应该有一个名为bundle.js的文件,它将是index.html将使用的文件。这是webpack的简约捆绑功能。你可以在这里了解更多


4

require在浏览器中不存在,因此可能会出现此错误。您需要使用诸如require.js或Browserify之类的东西。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.