使用 babel 时是否需要 require js?

IT技术 javascript ecmascript-6
2021-01-26 21:14:50

我正在试验 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个回答

使用 babel 时是否需要 require js?

你可能需要一些module加载器,但它不是必需的 RequireJS。您有多种选择。以下内容将帮助您入门。


rollup.jsrollup-plugin-babel

Rollup 是下一代 JavaScript module打包器。它本机理解 ES2015 module,并将生成一个不需要任何module加载器来操作的包。未使用的导出将从输出中修剪,这称为摇树。

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

  1. 用 babel 编译 ES6 代码,使用你选择的module格式
  2. 将编译后的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执行以下操作:

  1. 从文件系统中读取 ES6-7 module
  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 +浏览器化

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

使用 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插件。

gulp-rollup也可能是这个列表的一个很好的补充
2021-03-21 21:14:50
我自己从未测量过它,但我会假设人们会在分发之前缩小包,并且缩小可能会为本地人找到不同的名称,因此它们不会完全相同。Gzip 应该会找到公共部分(产生良好的压缩率),但浏览器仍然需要单独解析它们。最终它不应该是一个明显的开销,但是会有像我这样的人不喜欢重复的代码。
2021-04-03 21:14:50
我不明白为什么 Babel 不能自己做到这一点。我们正在使用 Babel 将我们所有的 JS 连接和缩小到一个文件中。为,例如,添加一个 polyfillPromise应该就像在列表中再添加一个文件一样简单。使用整个module加载器似乎是一种矫枉过正……无论如何:/+1
2021-04-05 21:14:50
这太该死的彻底了;谢谢。回复:每个文件都有重复的 Babel 样板 - 假设 gzip 几乎可以否定它是否正确?
2021-04-10 21:14:50
有道理,谢谢回复。此外,如果您必须在版本控制中备份或跟踪输出代码(未压缩文件大小成倍增加),或者您希望出于任何原因未缩小输出,这可能也很有意义。
2021-04-10 21:14:50

准系统 webpack 2

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

索引.html

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

脚本.js

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

形状.js

export class Circle {
  ...
}

2)有节点安装节点

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

$ npm install -g webpack

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

$ webpack scripts.js bundle.js

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

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