ฉันจำเป็นต้องใช้ js เมื่อฉันใช้ babel หรือไม่?


100

ฉันกำลังทดลองกับ ES6 และฉันใช้อึกเพื่อสร้างและ 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

หมายถึงสิ่งนี้ (หลัง. pip (babel ()) ในอึก)

var _shapes = require('shapes');

3
ใช่เนื่องจากrequireไม่มีอยู่ในเบราว์เซอร์คุณจึงต้องใช้เครื่องมือสร้างบางอย่างเช่น Require.js, Browserify หรือ Webpack
Jordan Running

1
อ่าการเพิ่ม browserify ใน googling ทำให้ฉันได้รับคำตอบขอบคุณ
jason

10
FWIW โปรดทราบว่าข้อความแสดงข้อผิดพลาดไม่ได้ระบุว่าคุณต้องการ need.js Babel แปลงโมดูลเป็น CommonJS ตามค่าเริ่มต้นซึ่งเป็นสิ่งที่โหนดใช้และกำหนดrequireฟังก์ชัน (อีกครั้งไม่เกี่ยวข้องกับ require.js) อย่างไรก็ตามคุณสามารถบอก Babel ให้แปลงโมดูลเป็นอย่างอื่นเช่น AMD หรือ UMD ซึ่งจะทำงานร่วมกับ require.js ไม่ว่าจะด้วยวิธีใดคุณต้องมีระบบเพื่อโหลดโมดูลในเบราว์เซอร์เนื่องจากเบราว์เซอร์ไม่ได้จัดเตรียมโมดูลไว้ตามค่าเริ่มต้น
Felix Kling

ดูได้ที่นี่: stackoverflow.com/questions/28125554/…
Todd

คำตอบ:


137

ฉันจำเป็นต้องใช้ js เมื่อฉันใช้ babel หรือไม่?

คุณอาจต้องการตัวโหลดโมดูล แต่ไม่จำเป็นต้องใช้ RequireJS คุณมีหลายทางเลือก สิ่งต่อไปนี้จะช่วยคุณในการเริ่มต้น


rollup.jsพร้อมrollup-plugin-babel

Rollup เป็นบันเดิลโมดูล JavaScript รุ่นใหม่ เข้าใจโมดูล ES2015 โดยกำเนิดและจะสร้างบันเดิลที่ไม่ต้องใช้ตัวโหลดโมดูลใด ๆ ในการทำงาน การส่งออกที่ไม่ได้ใช้จะถูกตัดออกจากผลผลิตเรียกว่าการเขย่าต้นไม้

ตอนนี้ฉันแนะนำให้ใช้ rollupjs เป็นการส่วนตัวเนื่องจากให้ผลลัพธ์ที่ชัดเจนที่สุดและง่ายต่อการติดตั้งอย่างไรก็ตามมันให้แง่มุมที่แตกต่างกับคำตอบ แนวทางอื่น ๆ ทั้งหมดทำดังต่อไปนี้:

  1. รวบรวมรหัส ES6 ด้วย babel ใช้รูปแบบโมดูลที่คุณเลือก
  2. เชื่อมต่อโมดูลที่คอมไพล์เข้าด้วยกันกับตัวโหลดโมดูลหรือใช้บันเดิลเลอร์ที่จะข้ามผ่านการอ้างอิงสำหรับคุณ

ด้วยสิ่งที่ rollupjs ไม่ได้ผลเช่นนี้ ที่นี่การรวบรวมเป็นขั้นตอนแรกแทนที่จะเป็น Babel เข้าใจเฉพาะโมดูล ES6 ตามค่าเริ่มต้น คุณต้องให้โมดูลรายการซึ่งการอ้างอิงจะถูกส่งผ่านและเชื่อมต่อกัน เนื่องจาก ES6 อนุญาตการส่งออกที่มีชื่อหลายรายการในโมดูล rollupjs จึงฉลาดพอที่จะตัดการส่งออกที่ไม่ได้ใช้ออกไปจึงทำให้ขนาดของชุดรวมลดลง น่าเสียดายที่ rollupjs-s parser ไม่เข้าใจไวยากรณ์> ES6 ดังนั้นจึงต้องรวบรวมโมดูล ES7 ก่อนที่ Rollup จะแยกวิเคราะห์ได้ แต่การคอมไพล์ไม่ควรส่งผลต่อการนำเข้า ES6 ทำได้โดยใช้rollup-plugin-babelปลั๊กอินที่มีbabel-preset-es2015-rollupค่าที่ตั้งไว้ล่วงหน้า (ค่าที่ตั้งไว้นี้เหมือนกับ es2015 ยกเว้นหม้อแปลงโมดูลและปลั๊กอินตัวช่วยภายนอก) ดังนั้นค่าสะสมจะทำสิ่งต่อไปนี้กับโมดูลของคุณหากตั้งค่าอย่างถูกต้อง:

  1. อ่านโมดูล ES6-7 ของคุณจากระบบไฟล์
  2. ปลั๊กอิน babel รวบรวมไว้ในหน่วยความจำ ES6
  3. ค่าสะสมแยกวิเคราะห์รหัส ES6 สำหรับการนำเข้าและส่งออก (โดยใช้ตัวแยกวิเคราะห์ลูกโอ๊กรวบรวมเป็นค่าสะสม)
  4. มันข้ามกราฟทั้งหมดและสร้างบันเดิลเดียว (ซึ่งอาจยังมีการอ้างอิงภายนอกและการเอ็กซ์พอร์ตของรายการอาจถูกส่งออกในรูปแบบที่คุณเลือก)

ตัวอย่าง nodejs build:

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

ตัวอย่างการสร้างอึกด้วย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

บาเบลมีแพคเกจเรียบร้อยเรียกว่า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 สำหรับตอนนี้ (กันยายน 2016) ฉันยังคงแนะนำให้ใช้ rollup กับ babel แม้ว่าความคิดเห็นของฉันอาจเปลี่ยนแปลงไปกับ WebPack 2 รุ่นแรกอย่าลังเลที่จะพูดคุยเกี่ยวกับความคิดเห็นของคุณในความคิดเห็น


ไปป์ไลน์การรวบรวมแบบกำหนดเอง

บางครั้งคุณต้องการควบคุมกระบวนการคอมไพล์ให้มากขึ้น คุณสามารถใช้ไปป์ไลน์ของคุณเองได้ดังนี้:

ขั้นแรกคุณต้องกำหนดค่า babel เพื่อใช้โมดูล amd โดยค่าเริ่มต้น babel จะย้ายไปยังโมดูล CommonJS ซึ่งมีความซับซ้อนเล็กน้อยในการจัดการในเบราว์เซอร์แม้ว่า browserify จะจัดการกับมันได้ดีก็ตาม

  • Babel 5: ใช้{ modules: 'amdStrict', ... }ตัวเลือก
  • Babel 6: ใช้es2015-modules-amdปลั๊กอิน

อย่าลืมเปิดmoduleIds: trueตัวเลือก

ตรวจสอบรหัส Transpiled สำหรับชื่อโมดูลที่สร้างขึ้นมักจะมีความไม่ตรงกันระหว่างโมดูลที่กำหนดและโมดูลที่จำเป็น ดูsourceRoot และ moduleRoot

สุดท้ายคุณต้องมีตัวโหลดโมดูลบางประเภท แต่ก็ไม่จำเป็นต้องใช้นม มีอัลมอนด์เป็นชิมเล็ก ๆ ที่ต้องใช้งานได้ดี คุณสามารถใช้ของคุณเอง:

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ปลั๊กอิน


1
นี่มันเปื้อนเลือดมาก ขอบคุณ. Re: เอกสารสำเร็จรูป Babel ที่ซ้ำกันต่อไฟล์ - จะถูกต้องหรือไม่ถ้าสมมติว่า gzip จะปฏิเสธสิ่งนั้นทั้งหมด
iono

1
ฉันไม่เคยวัดด้วยตัวเอง แต่ฉันคิดว่าจะมีการย่อกลุ่มก่อนการแจกจ่ายและการลดขนาดอาจพบชื่อที่แตกต่างกันสำหรับคนในพื้นที่ดังนั้นจึงไม่เหมือนกันทุกประการ Gzip ควรค้นหาชิ้นส่วนทั่วไป (ส่งผลให้มีอัตราส่วนการบีบอัดที่ดี) แต่เบราว์เซอร์ยังคงต้องแยกวิเคราะห์ทีละส่วน ท้ายที่สุดแล้วมันไม่ควรเป็นค่าใช้จ่ายที่เห็นได้ชัดเจน แต่จะมีคนอย่างฉันที่ไม่ชอบรหัสซ้ำ
Tamas Hegedus

พอใช้ขอบคุณสำหรับการตอบกลับ มันอาจจะสมเหตุสมผลมากเช่นกันในกรณีที่คุณต้องสำรองหรือติดตามโค้ดเอาต์พุตในการควบคุมเวอร์ชัน (ที่ขนาดไฟล์ที่ไม่บีบอัดคูณ) หรือในกรณีที่คุณต้องการให้เอาต์พุตไม่มีการย่อไม่ว่าด้วยเหตุผลใดก็ตาม
iono

gulp-rollupอาจเป็นส่วนเสริมที่ดีในรายการนี้เช่นกัน
GGG

@GGG เพิ่มตัวอย่างอึก น่าเสียดายที่ไม่มีตัวอย่างใดใช้งานได้ในขณะนี้บน windows โปรดดูคำอธิบายด้านบนของรหัส
Tamas Hegedus

8

barebones webpack 2

1) หากนี่คือไดเรกทอรีรากของคุณ:

index.html

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

scripts.js

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

shape.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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.