Benötige ich js, wenn ich babel benutze?

98

Ich experimentiere mit ES6 und ich benutze Schluck, um zu bauen und Babel, um zu ES5 zu transpilieren. Die Ausgabe wird nicht im Knoten ausgeführt, sondern nur mit einer .htm-Datei mit einem Tag verknüpft. Ich denke, ich muss hinzufügen

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

oder etwas ähnliches.

Ich versuche zu importieren / exportieren.

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

}

Fehler ist

Uncaught ReferenceError: require is not defined

Bezieht sich darauf (nach .pipe (babel ()) in gulp)

var _shapes = require('shapes');
Jason
quelle
3
Ja, da requireder Browser nicht vorhanden ist, müssen Sie ein Build-Tool wie Require.js, Browserify oder Webpack verwenden.
Jordan läuft
1
Ahh, das Hinzufügen von browserify zu meinem Googeln hat mir die Antwort gegeben, danke.
Jason
10
FWIW, beachten Sie, dass die Fehlermeldung nicht anzeigt, dass Sie require.js benötigen. Babel konvertiert Module standardmäßig in CommonJS. Dies wird von Node verwendet und definiert eine requireFunktion (wiederum nichts mit require.js zu tun). Allerdings können Sie Babel sagen Module etwas zu konvertieren sonst , zB AMD oder UMD, die dann mit require.js funktionieren würde. In beiden Fällen benötigen Sie ein System zum Laden von Modulen in den Browser, da der Browser (noch) nicht standardmäßig eines bereitstellt.
Felix Kling

Antworten:

136

Benötige ich js, wenn ich babel benutze?

Möglicherweise benötigen Sie einen Modullader, dies ist jedoch nicht erforderlich. RequireJS. Sie haben mehrere Möglichkeiten. Das Folgende hilft Ihnen beim Einstieg.


rollup.js mit rollup-plugin-babel

Rollup ist ein JavaScript-Modulbündler der nächsten Generation. Es versteht ES2015-Module von Haus aus und erstellt ein Bundle, für dessen Betrieb kein Modullader erforderlich ist. Nicht verwendete Exporte werden von der Ausgabe abgeschnitten, dies wird als Baumschütteln bezeichnet.

Jetzt empfehle ich persönlich die Verwendung von rollupjs, da es die klarste Ausgabe erzeugt und einfach einzurichten ist. Die Antwort erhält jedoch einen anderen Aspekt. Alle anderen Ansätze machen Folgendes:

  1. Kompilieren Sie den ES6-Code mit babel und verwenden Sie das Modulformat Ihrer Wahl
  2. Verketten Sie die kompilierten Module zusammen mit einem Modullader ODER verwenden Sie einen Bundler, der die Abhängigkeiten für Sie durchläuft.

Mit rollupjs funktionieren die Dinge nicht wirklich so. Hier ist Rollup der erste Schritt anstelle von Babel. Standardmäßig werden nur ES6-Module verstanden. Sie müssen ein Eingabemodul angeben, dessen Abhängigkeiten durchlaufen und verkettet werden. Da ES6 mehrere benannte Exporte in einem Modul zulässt, ist rollupjs intelligent genug, um nicht verwendete Exporte zu entfernen und so die Bundle-Größe zu verringern. Leider versteht der Parser von rollupjs-s die> ES6-Syntax nicht, sodass ES7-Module kompiliert werden müssen, bevor sie vom Rollup analysiert werden. Die Kompilierung sollte jedoch keine Auswirkungen auf die ES6-Importe haben. Dies erfolgt mithilfe des rollup-plugin-babelPlugins mit der babel-preset-es2015-rollupVoreinstellung (diese Voreinstellung ist dieselbe wie die es2015, mit Ausnahme des Modultransformators und des Plugins für externe Helfer). Das Rollup führt bei korrekter Einrichtung Folgendes mit Ihren Modulen aus:

  1. Liest Ihr ES6-7-Modul aus dem Dateisystem
  2. Das Babel-Plugin kompiliert es zu ES6 im Speicher
  3. Rollup analysiert den ES6-Code für Importe und Exporte (mit dem in Rollup kompilierten Eichel-Parser)
  4. Es durchläuft das gesamte Diagramm und erstellt ein einzelnes Bundle (das möglicherweise noch externe Abhängigkeiten aufweist und dessen Exporte möglicherweise in einem Format Ihrer Wahl exportiert werden).

Beispiel für den Build von 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));

Beispiel Grunz Build mit Grunz-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"]
        }
      }
    }
  });
}

Beispiel für einen Gulp-Build mit 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 hat ein ordentliches Paket namens babelify . Die Verwendung ist einfach und unkompliziert:

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

oder Sie können es von node.js verwenden:

$ 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"));

Dadurch wird Ihr Code sofort transpiliert und verkettet. Browserify's .bundlewird einen netten kleinen CommonJS-Loader enthalten und Ihre transpilierten Module in Funktionen organisieren. Sie können sogar relative Importe haben.

Beispiel:

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

Zum Kompilieren einfach node build.jsin Ihrem Projektstamm ausführen .


Babel + WebPack

Kompilieren Sie Ihren gesamten Code mit babel. Ich empfehle Ihnen, den amd-Modultransformator ( babel-plugin-transform-es2015-modules-amdin Babel 6 genannt) zu verwenden. Danach bündeln Sie Ihre kompilierten Quellen mit WebPack.

WebPack 2 ist da! Es versteht native ES6-Module und führt (oder simuliert) das Schütteln von Bäumen mithilfe der in Babili integrierten Eliminierung von totem Code durch. Im Moment (September 2016) würde ich immer noch vorschlagen, Rollup mit Babel zu verwenden, obwohl sich meine Meinung mit der ersten Version von WebPack 2 ändern könnte. Sie können Ihre Meinung gerne in den Kommentaren diskutieren.


Benutzerdefinierte Kompilierungspipeline

Manchmal möchten Sie mehr Kontrolle über den Kompilierungsprozess haben. Sie können Ihre eigene Pipeline folgendermaßen implementieren:

Zuerst müssen Sie babel für die Verwendung von amd-Modulen konfigurieren. Standardmäßig transpiliert babel in CommonJS-Module, was im Browser etwas kompliziert zu handhaben ist, obwohl browserify es schafft, sie auf nette Weise zu handhaben.

  • Babel 5: { modules: 'amdStrict', ... }Option verwenden
  • Babel 6: benutze das es2015-modules-amdPlugin

Vergessen Sie nicht, die moduleIds: trueOption zu aktivieren.

Überprüfen Sie den transpilierten Code auf generierte Modulnamen. Oft gibt es Abweichungen zwischen definierten und erforderlichen Modulen. Siehe sourceRoot und moduleRoot .

Schließlich müssen Sie eine Art Modullader haben, aber es ist nicht unbedingt erforderlich. Es gibt Mandeln , eine winzige Unterlegscheibe, die gut funktioniert. Sie können sogar Ihre eigenen implementieren:

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

Am Ende können Sie einfach den Loader-Shim und die kompilierten Module miteinander verketten und darauf ein uglify ausführen.


Babels Boilerplate-Code wird in jedem Modul dupliziert

Standardmäßig kompilieren die meisten der oben genannten Methoden jedes Modul mit babel einzeln und verketten sie dann miteinander. Das macht babelify auch. Wenn Sie sich jedoch den kompilierten Code ansehen, sehen Sie, dass Babel am Anfang jeder Datei eine Menge Boilerplate einfügt. Die meisten davon werden in allen Dateien dupliziert.

Um dies zu verhindern, können Sie das babel-plugin-transform-runtimePlugin verwenden.

Tamas Hegedus
quelle
1
Das ist so verdammt gründlich; Danke. Betreff: das doppelte Babel-Boilerplate pro Datei - wäre es richtig anzunehmen, dass gzip das alles andere als negieren würde?
Iono
1
Ich habe es nie selbst gemessen, aber ich würde annehmen, dass man das Bündel vor der Verteilung minimieren würde, und die Verkleinerung wird wahrscheinlich unterschiedliche Namen für Einheimische finden, so dass sie nicht genau gleich sind. Gzip sollte die gemeinsamen Teile finden (was zu einem guten Komprimierungsverhältnis führt), aber der Browser muss sie immer noch einzeln analysieren. Letztendlich sollte es kein spürbarer Overhead sein, aber es wird Leute wie mich geben, die doppelten Code einfach nicht mögen.
Tamas Hegedus
Fair genug, danke für die Antwort. Es wäre wahrscheinlich auch sehr sinnvoll, wenn Sie den Ausgabecode in der Versionskontrolle sichern oder verfolgen müssten (wenn sich die unkomprimierte Dateigröße vervielfacht) oder wenn Sie möchten, dass die Ausgabe aus irgendeinem Grund nicht minimiert wird.
Iono
Schluck-Rollup könnte auch eine gute Ergänzung zu dieser Liste sein
GGG
@GGG Schluckbeispiel hinzugefügt. Leider funktioniert derzeit keines der Beispiele unter Windows, siehe die Erklärung oben in den Codes.
Tamas Hegedus
8

Barebones Webpack 2

1) Wenn dies Ihr Stammverzeichnis ist:

index.html

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

scripts.js

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

Formen.js

export class Circle {
  ...
}

2) Knoten installiert Knoten

3) Führen Sie den folgenden Befehl in Ihrem Terminal aus:

$ npm install -g webpack

5) Führen Sie in Ihrem Stammverzeichnis Folgendes aus:

$ webpack scripts.js bundle.js

Sie sollten jetzt eine Datei namens bundle.js in Ihrem Stammverzeichnis haben, die die Datei ist, die Ihre index.html verbraucht. Dies ist eine minimalistische Bündelungsfunktion von Webpack. Sie können erfahren Sie mehr hier

Isaac Pak
quelle
4

requireist im Browser nicht vorhanden, daher wird dieser Fehler erwartet. Sie müssen so etwas wie require.js oder Browserify verwenden.

Djechlin
quelle