【问题标题】:Do I need require js when I use babel?使用 babel 时需要 require js 吗?
【发布时间】:2015-10-14 03:10:47
【问题描述】:

我正在尝试使用 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

指this(在gulp中的.pipe(babel())之后)

var _shapes = require('shapes');

【问题讨论】:

  • 是的,因为require在浏览器中不存在,你需要使用一些构建工具,比如Require.js、Browserify或者Webpack。
  • 啊,将 browserify 添加到我的谷歌搜索中得到了答案,谢谢。
  • FWIW,请注意错误消息并不表示您需要 require.js 。 Babel 默认将模块转换为 CommonJS,这是 Node 使用的,它定义了一个 require 函数(同样,与 require.js 无关)。但是,you can tell Babel to convert modules to something else,例如AMD 或 UMD,然后可以与 require.js 一起使用。无论哪种方式,您都需要一个系统来在浏览器中加载模块,因为浏览器默认不提供模块(目前)。
  • 对于 2020 年左右来到这里的人,您可以使用 'transform-modules-amd' 插件而无需其他库。参考babeljs.io/docs/en/babel-plugin-transform-modules-amd

标签: javascript ecmascript-6


【解决方案1】:

准系统 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) 已安装节点node

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

$ npm install -g webpack

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

$ webpack scripts.js bundle.js

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

【讨论】:

    【解决方案2】:

    使用 babel 时需要 require js 吗?

    你可能需要一些模块加载器,但这不是必需的。你有几个选择。以下内容将帮助您入门。


    rollup.jsrollup-plugin-babel

    Rollup 是下一代 JavaScript 模块捆绑器。它原生地理解 ES2015 模块,并将生成一个不需要任何模块加载器来操作的包。未使用的导出将从输出中删除,这称为 tree-shaking。

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

    1. 用 babel 编译 ES6 代码,使用你选择的模块格式
    2. 将已编译的模块与模块加载器连接起来,或者使用一个为您遍历依赖项的捆绑器。

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

    1. 从文件系统中读取 ES6-7 模块
    2. babel 插件在内存中将其编译为 ES6
    3. rollup 解析用于导入和导出的 ES6 代码(使用 acorn 解析器,编译成 rollup)
    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 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 插件。

    【讨论】:

    • 这太彻底了;谢谢。回复:每个文件重复的 Babel 样板 - 假设 gzip 几乎否定它是正确的吗?
    • 我自己从未测量过它,但我会假设在分发之前会缩小捆绑包,并且缩小可能会为本地人找到不同的名称,因此它们不会完全相同。 Gzip 应该找到共同的部分(产生良好的压缩比),但浏览器仍然必须单独解析它们。最终它不应该是一个明显的开销,但是会有像我这样不喜欢重复代码的人。
    • 很公平,感谢您的回复。此外,如果您必须在版本控制中备份或跟踪输出代码(未压缩的文件大小成倍增加),或者出于任何原因您希望输出未缩小,这可能也很有意义。
    • gulp-rollup 可能也是这个列表的一个很好的补充
    • 我不明白为什么 Babel 不能自己做到这一点。我们使用 Babel 在一个文件中连接和缩小我们所有的 JS。为Promise 添加一个 polyfill 应该像在列表中添加一个文件一样简单。使用整个模块加载器似乎太过分了......:/ +1反正
    【解决方案3】:

    require 在浏览器中不存在,所以这个错误是预料之中的。你需要使用 require.js 或 Browserify 之类的东西。

    【讨论】:

      猜你喜欢
      • 2017-02-19
      • 2017-01-04
      • 2022-10-13
      • 2020-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-04
      相关资源
      最近更新 更多