Tôi có cần yêu cầu j khi tôi sử dụng babel không?


98

Tôi đang thử nghiệm với ES6 và tôi đang sử dụng gulp để xây dựng và babel để chuyển sang ES5. Đầu ra không được chạy trong nút, chỉ được liên kết đến từ tệp .htm bằng thẻ. Tôi nghĩ tôi cần thêm

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

hoặc điều tương tự.

Tôi đang cố gắng nhập / xuất.

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

}

Lỗi là

Uncaught ReferenceError: require is not defined

Đề cập đến điều này (sau .pipe (babel ()) trong gulp)

var _shapes = require('shapes');

3
Có, vì requirekhông tồn tại trong trình duyệt, bạn cần sử dụng một số công cụ xây dựng như Requi.js, Browserify hoặc Webpack.
Jordan Running

1
Ahh, thêm Browserify vào googling của tôi đã giúp tôi có câu trả lời, cảm ơn bạn.
jason

10
FWIW, lưu ý rằng thông báo lỗi không chỉ ra rằng bạn cần phải có request.js. Babel chuyển đổi các mô-đun thành CommonJS theo mặc định, đó là những gì Node sử dụng và định nghĩa mộtrequire chức năng (một lần nữa, không liên quan gì đến request.js). Tuy nhiên, bạn có thể yêu cầu Babel chuyển đổi mô-đun sang một thứ khác , chẳng hạn như AMD hoặc UMD, sau đó sẽ hoạt động với request.js. Dù bằng cách nào, bạn cần một hệ thống để tải các mô-đun trong trình duyệt, vì trình duyệt không cung cấp (chưa) theo mặc định.
Felix Kling

Câu trả lời:


136

Tôi có cần yêu cầu j khi tôi sử dụng babel không?

Bạn có thể cần một số trình tải mô-đun, nhưng không cần thiết phải có RequestJS. Bạn có một số lựa chọn. Những điều sau đây sẽ giúp bạn bắt đầu.


rollup.js với rollup-plugin-babel

Rollup là một gói mô-đun JavaScript thế hệ tiếp theo. Nó hiểu các mô-đun ES2015 một cách nguyên bản và sẽ tạo ra một gói mà không cần bất kỳ trình tải mô-đun nào để hoạt động. Hàng xuất khẩu không được sử dụng sẽ bị cắt khỏi đầu ra, nó được gọi là rung cây.

Bây giờ cá nhân tôi khuyên bạn nên sử dụng rollupjs, vì nó tạo ra đầu ra rõ ràng nhất và dễ thiết lập, tuy nhiên, nó mang lại một khía cạnh khác cho câu trả lời. Tất cả các cách tiếp cận khác làm như sau:

  1. Biên dịch mã ES6 với babel, sử dụng định dạng mô-đun bạn chọn
  2. Nối các mô-đun đã biên dịch cùng với một trình tải mô-đun HOẶC sử dụng một trình gói sẽ duyệt các phần phụ thuộc cho bạn.

Với rollupjs, mọi thứ không thực sự hoạt động theo cách này. Ở đây, cuộn lên là bước đầu tiên, thay vì babel. Nó chỉ hiểu các mô-đun ES6 theo mặc định. Bạn phải cung cấp một mô-đun mục nhập mà trong đó các phần phụ thuộc sẽ được duyệt và nối. Vì ES6 cho phép nhiều tệp xuất được đặt tên trong một mô-đun, rollupjs đủ thông minh để loại bỏ các tệp xuất không sử dụng, do đó thu nhỏ kích thước gói. Thật không may, trình phân tích cú pháp rollupjs-s không hiểu> cú pháp ES6, vì vậy các mô-đun ES7 phải được biên dịch trước khi cuộn lên phân tích cú pháp chúng, nhưng việc biên dịch sẽ không ảnh hưởng đến việc nhập ES6. Nó được thực hiện bằng cách sử dụng rollup-plugin-babelplugin có babel-preset-es2015-rollupcài đặt sẵn (cài đặt trước này giống với cài đặt trước es2015, ngoại trừ biến áp mô-đun và plugin trình trợ giúp bên ngoài). Vì vậy, cuộn lên sẽ thực hiện những việc sau với các mô-đun của bạn nếu được thiết lập chính xác:

  1. Đọc mô-đun ES6-7 của bạn từ hệ thống tệp
  2. Plugin babel biên dịch nó thành ES6 trong bộ nhớ
  3. rollup phân tích cú pháp mã ES6 cho nhập và xuất (sử dụng trình phân tích cú pháp acorn, được biên dịch thành cuộn lên)
  4. nó đi ngang qua toàn bộ biểu đồ và tạo một gói duy nhất (vẫn có thể có các phụ thuộc bên ngoài và các xuất của mục nhập có thể được xuất theo định dạng bạn chọn)

Bản dựng nodejs mẫu:

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

Ví dụ về bản dựng grunt với grunt-rollup

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

Ví dụ về bản dựng gulp với gulp-rollup

// 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 có một gói gọn gàng được gọi là babelify . Cách sử dụng của nó rất đơn giản và dễ hiểu:

$ 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 ] ]

hoặc bạn có thể sử dụng nó từ 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"));

Điều này sẽ chuyển và nối mã của bạn cùng một lúc. Browserify's.bundle sẽ bao gồm một trình tải CommonJS nhỏ xinh, và sẽ tổ chức các mô-đun được chuyển đổi của bạn thành các chức năng. Bạn thậm chí có thể có hàng nhập khẩu tương đối.

Thí dụ:

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

Để biên dịch chỉ cần chạy node build.jstrong gốc dự án của bạn.


Babel + WebPack

Biên dịch tất cả mã của bạn bằng cách sử dụng babel. Tôi khuyên bạn nên sử dụng biến áp mô-đun amd (được gọi babel-plugin-transform-es2015-modules-amdtrong babel 6). Sau đó, gói các nguồn đã biên dịch của bạn với WebPack.

WebPack 2 đã ra mắt! Nó hiểu các mô-đun ES6 bản địa và sẽ thực hiện (hoặc đúng hơn là mô phỏng) rung cây bằng cách sử dụng loại bỏ mã chết nội trang babili -s. Hiện tại (tháng 9 năm 2016) tôi vẫn đề xuất sử dụng bản tổng hợp với babel, mặc dù ý kiến ​​của tôi có thể thay đổi với bản phát hành đầu tiên của WebPack 2. Vui lòng thảo luận ý kiến ​​của bạn trong phần bình luận.


Quy trình biên dịch tùy chỉnh

Đôi khi bạn muốn kiểm soát nhiều hơn quá trình biên dịch. Bạn có thể triển khai đường dẫn của riêng mình như sau:

Đầu tiên, bạn phải cấu hình babel để sử dụng mô-đun amd. Theo mặc định, babel chuyển đổi sang các mô-đun CommonJS, điều này hơi phức tạp để xử lý trong trình duyệt, mặc dù Browserify quản lý để xử lý chúng theo một cách tốt đẹp.

  • Babel 5: { modules: 'amdStrict', ... }tùy chọn sử dụng
  • Babel 6: sử dụng es2015-modules-amdplugin

Đừng quên bật moduleIds: true tùy chọn.

Kiểm tra mã chuyển đổi để biết các tên mô-đun đã tạo, thường có sự không khớp giữa các mô-đun được xác định và yêu cầu. Xem sourceRoot và moduleRoot .

Cuối cùng, bạn phải có một số loại trình tải mô-đun, nhưng nó không phải là yêu cầu bắt buộc. Có almondjs , một miếng chêm nhỏ yêu cầu hoạt động tốt. Bạn thậm chí có thể triển khai của riêng mình:

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

Cuối cùng, bạn chỉ có thể nối miếng đệm bộ nạp và các mô-đun đã biên dịch lại với nhau, và chạy một chương trình không phù hợp trên đó.


Mã chương trình soạn sẵn của Babel được sao chép trong mọi mô-đun

Theo mặc định, hầu hết các phương thức trên đều biên dịch từng mô-đun với babel riêng lẻ, sau đó nối chúng lại với nhau. Đó là những gì babelify cũng làm. Nhưng nếu bạn nhìn vào mã đã biên dịch, bạn sẽ thấy rằng babel chèn rất nhiều bản soạn sẵn vào đầu mỗi tệp, hầu hết chúng đều được sao chép trên tất cả các tệp.

Để ngăn chặn điều này, bạn có thể sử dụng babel-plugin-transform-runtimeplugin.


1
Điều này là rất kỹ lưỡng; cảm ơn bạn. Re: bản sao chép Babel trùng lặp trên mỗi tệp - có đúng không khi cho rằng gzip sẽ phủ nhận tất cả điều đó?
iono

1
Tôi chưa bao giờ tự mình đo lường nó, nhưng tôi sẽ giả định rằng người ta sẽ thu nhỏ gói trước khi phân phối và việc thu nhỏ có thể sẽ tìm thấy các tên khác nhau cho người dân địa phương, vì vậy chúng sẽ không hoàn toàn giống nhau. Gzip sẽ tìm thấy các phần chung (dẫn đến tỷ lệ nén tốt), nhưng trình duyệt vẫn phải phân tích cú pháp riêng lẻ. Cuối cùng thì nó không phải là một chi phí đáng chú ý, nhưng sẽ có những người như tôi không thích mã trùng lặp.
Tamas Hegedus

Đủ công bằng, cảm ơn vì đã phản hồi. Nó cũng có thể có ý nghĩa trong trường hợp bạn phải sao lưu hoặc theo dõi mã đầu ra trong kiểm soát phiên bản (nơi kích thước tệp không nén tăng lên gấp bội) hoặc khi bạn muốn đầu ra không bị đơn giản hóa vì bất kỳ lý do gì.
iono

ngụm-rollup có thể là một bổ sung tuyệt vời vào danh sách này quá
GGG

@GGG Đã thêm ví dụ về gulp. Rất tiếc, hiện tại không có ví dụ nào hoạt động trên windows, hãy xem phần giải thích ở phần trên cùng của mã.
Tamas Hegedus

8

webpack 2

1) Nếu đây là thư mục gốc của bạn:

index.html

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

scripts.js

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

shape.js

export class Circle {
  ...
}

2) có nút đã cài đặt nút

3) chạy lệnh sau trong thiết bị đầu cuối của bạn:

$ npm install -g webpack

5) trong thư mục gốc của bạn chạy như sau:

$ webpack scripts.js bundle.js

Bây giờ bạn sẽ có một tệp có tên là pack.js trong thư mục gốc, tệp này sẽ là tệp mà index.html của bạn sẽ sử dụng. Đây là một tính năng gói tối giản từ webpack. Bạn có thể tìm hiểu thêm tại đây


4

requirekhông tồn tại trong trình duyệt, vì vậy lỗi này được mong đợi. Bạn cần sử dụng một cái gì đó giống như request.js hoặc Browserify.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.