Apakah saya memerlukan require js saat menggunakan babel?

98

Saya bereksperimen dengan ES6, dan saya menggunakan gulp untuk membangun dan babel untuk ditranspilasi ke ES5. Outputnya tidak dijalankan dalam node, hanya ditautkan ke dari file .htm dengan tag. Saya pikir saya perlu menambahkan

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

atau semacam itu.

Saya mencoba untuk mengimpor / mengekspor.

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

}

Kesalahan adalah

Uncaught ReferenceError: require is not defined

Mengacu pada ini (setelah .pipe (babel ()) di gulp)

var _shapes = require('shapes');
jason
sumber
3
Ya, karena requiretidak ada di browser, Anda perlu menggunakan beberapa alat build seperti Require.js, Browserify atau Webpack.
Jordan Menjalankan
1
Ahh, menambahkan browserify ke googling saya memberi saya jawabannya, terima kasih.
jason
10
FWIW, perhatikan bahwa pesan kesalahan tidak menunjukkan bahwa Anda memerlukan require.js. Babel mengonversi modul ke CommonJS secara default, yang digunakan Node dan yang mendefinisikan requirefungsi (sekali lagi, tidak ada hubungannya dengan require.js). Namun, Anda dapat memberi tahu Babel untuk mengonversi modul ke modul lain , misalnya AMD atau UMD, yang kemudian akan berfungsi dengan require.js. Bagaimanapun, Anda memerlukan sistem untuk memuat modul di browser, karena browser tidak menyediakan modul secara default (belum).
Felix Kling

Jawaban:

136

Apakah saya memerlukan require js saat menggunakan babel?

Anda mungkin membutuhkan beberapa modul loader, tetapi itu tidak perlu RequireJS. Anda punya beberapa pilihan. Berikut ini akan membantu Anda untuk memulai.


rollup.js dengan rollup-plugin-babel

Rollup adalah bundler modul JavaScript generasi berikutnya. Ini memahami modul ES2015 secara native, dan akan menghasilkan bundel yang tidak memerlukan modul loader apa pun untuk beroperasi. Ekspor yang tidak digunakan akan dipotong dari output, ini disebut gemetar pohon.

Sekarang saya pribadi merekomendasikan menggunakan rollupjs, karena menghasilkan output paling jelas, dan mudah diatur, namun memberikan aspek yang berbeda untuk jawabannya. Semua pendekatan lainnya melakukan yang berikut:

  1. Kompilasi kode ES6 dengan babel, gunakan format modul pilihan Anda
  2. Gabungkan modul yang telah dikompilasi bersama dengan modul loader ATAU gunakan bundler yang akan melintasi dependensi untuk Anda.

Dengan rollupjs hal-hal tidak benar-benar berfungsi seperti ini. Di sini, rollup adalah langkah pertama, bukan babel. Ini hanya memahami modul ES6 secara default. Anda harus memberikan modul entri yang dependensinya akan dilintasi dan digabungkan. Karena ES6 mengizinkan beberapa ekspor bernama dalam satu modul, rollupj cukup pintar untuk menghapus ekspor yang tidak digunakan, sehingga memperkecil ukuran paket. Sayangnya parser rollupjs-s tidak memahami sintaksis> ES6, jadi modul ES7 harus dikompilasi sebelum rollup mem-parsainya, tetapi kompilasi tidak akan memengaruhi impor ES6. Ini dilakukan dengan menggunakan rollup-plugin-babelplugin dengan babel-preset-es2015-rolluppreset (preset ini sama dengan es2015, kecuali modul transformer dan plugin external-helpers). Jadi rollup akan melakukan hal berikut dengan modul Anda jika diatur dengan benar:

  1. Membaca modul ES6-7 Anda dari sistem file
  2. Plugin babel mengkompilasinya menjadi ES6 di memori
  3. rollup mem-parsing kode ES6 untuk impor dan ekspor (menggunakan acorn parser, dikompilasi menjadi rollup)
  4. itu melintasi seluruh grafik, dan membuat satu bundel (yang mungkin masih memiliki ketergantungan eksternal, dan ekspor entri mungkin diekspor, dalam format pilihan Anda)

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

Contoh build grunt dengan 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"]
        }
      }
    }
  });
}

Contoh membangun gulp dengan 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 memiliki paket rapi yang disebut babelify . Penggunaannya sederhana dan mudah:

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

atau Anda dapat menggunakannya dari 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"));

Ini akan mentranspilasi dan menggabungkan kode Anda sekaligus. Browserify's.bundle akan menyertakan pemuat CommonJS kecil yang bagus, dan akan mengatur modul transparan Anda ke dalam fungsi. Anda bahkan dapat memiliki impor relatif.

Contoh:

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

Untuk mengkompilasi, jalankan saja node build.jsdi root proyek Anda.


Babel + WebPack

Kompilasi semua kode Anda menggunakan babel. Saya merekomendasikan Anda untuk menggunakan transformator modul amd (disebut babel-plugin-transform-es2015-modules-amddalam babel 6). Setelah itu bundel sumber yang Anda kompilasi dengan WebPack.

WebPack 2 sudah keluar! Ia memahami modul ES6 asli, dan akan melakukan (atau lebih tepatnya mensimulasikan) pohon gemetar menggunakan eliminasi kode mati bawaan babili -s. Untuk saat ini (September 2016) saya tetap menyarankan untuk menggunakan rollup dengan babel, meskipun pendapat saya mungkin berubah dengan rilis pertama WebPack 2. Jangan ragu untuk mendiskusikan pendapat Anda di kolom komentar.


Pipeline kompilasi kustom

Terkadang Anda ingin memiliki kontrol lebih atas proses kompilasi. Anda dapat menerapkan pipeline Anda sendiri seperti ini:

Pertama, Anda harus mengkonfigurasi babel untuk menggunakan modul amd. Secara default babel transpiles ke modul CommonJS, yang sedikit rumit untuk ditangani di browser, meskipun browserify berhasil menanganinya dengan cara yang baik.

  • Babel 5: gunakan { modules: 'amdStrict', ... }opsi
  • Babel 6: gunakan es2015-modules-amdplugin

Jangan lupa untuk mengaktifkan moduleIds: trueopsinya.

Periksa kode transparan untuk nama modul yang dihasilkan, sering kali ada ketidaksesuaian antara modul yang ditentukan dan yang diperlukan. Lihat sourceRoot dan moduleRoot .

Akhirnya, Anda harus memiliki beberapa jenis modul loader, tetapi itu tidak perlu membutuhkanjs. Ada almondjs , shim kecil yang bekerja dengan baik. Anda bahkan dapat menerapkannya sendiri:

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

Pada akhirnya, Anda cukup menggabungkan shim loader dan modul yang dikompilasi, dan menjalankan uglify padanya.


Kode boilerplate Babel diduplikasi di setiap modul

Secara default, sebagian besar metode di atas mengkompilasi setiap modul dengan babel satu per satu, dan kemudian menggabungkannya. Itu juga yang dilakukan babelify. Tetapi jika Anda melihat kode yang dikompilasi, Anda melihat bahwa babel menyisipkan banyak boilerplate di awal setiap file, kebanyakan dari mereka digandakan di semua file.

Untuk mencegahnya, Anda dapat menggunakan babel-plugin-transform-runtimeplugin.

Tamas Hegedus
sumber
1
Ini sangat teliti; Terima kasih. Re: duplikat boilerplate Babel per file - apakah benar untuk mengasumsikan bahwa gzip hanya akan meniadakannya?
iono
1
Saya tidak pernah mengukurnya sendiri, tetapi saya berasumsi bahwa seseorang akan mengecilkan bundel sebelum didistribusikan, dan minifikasi tersebut mungkin akan menemukan nama yang berbeda untuk penduduk setempat, jadi mereka tidak akan sama persis. Gzip harus menemukan bagian yang umum (menghasilkan rasio kompresi yang baik), tetapi browser masih harus menguraikannya satu per satu. Pada akhirnya ini seharusnya tidak menjadi overhead yang terlihat, tetapi akan ada orang seperti saya yang tidak suka kode duplikat.
Tamas Hegedus
Cukup adil, terima kasih atas tanggapannya. Ini mungkin akan sangat masuk akal, juga, dalam kasus di mana Anda harus mencadangkan atau melacak kode keluaran dalam kontrol versi (di mana ukuran file yang tidak dikompresi berlipat ganda) atau di mana Anda ingin keluaran tidak diminimalkan karena alasan apa pun.
iono
gulp-rollup mungkin merupakan tambahan yang bagus untuk daftar ini juga
GGG
@GGG Menambahkan contoh gulp. Sayangnya tidak ada contoh yang berfungsi saat ini di windows, lihat penjelasan di atas kode.
Tamas Hegedus
8

barebones webpack 2

1) Jika ini adalah direktori root Anda:

index.html

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

scripts.js

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

bentuk. js

export class Circle {
  ...
}

2) memiliki node terpasang node

3) jalankan perintah berikut di terminal Anda:

$ npm install -g webpack

5) di direktori root Anda, jalankan perintah berikut:

$ webpack scripts.js bundle.js

Anda sekarang harus memiliki file bernama bundle.js di direktori root Anda yang akan menjadi file yang akan digunakan index.html Anda. Ini adalah fitur bundling minimalis dari webpack. Anda dapat mempelajari lebih lanjut di sini

Isaac Pak
sumber
4

requiretidak ada di browser, jadi kesalahan ini sudah diperkirakan. Anda perlu menggunakan sesuatu seperti require.js atau Browserify.

djechlin.dll
sumber