Ai-je besoin de js lorsque j'utilise babel?

98

Im expérimentant avec ES6, et Im utilisant gulp pour construire et babel pour transpiler vers ES5. La sortie n'est pas exécutée dans node, mais simplement liée à partir d'un fichier .htm avec une balise. Je pense que je dois ajouter

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

ou quelque chose comme ça.

J'essaye d'importer / exporter.

////////////////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'erreur est

Uncaught ReferenceError: require is not defined

Fait référence à ceci (après .pipe (babel ()) dans gulp)

var _shapes = require('shapes');
Jason
la source
3
Oui, car il requiren'existe pas dans le navigateur, vous devez utiliser un outil de construction comme Require.js, Browserify ou Webpack.
Jordan Running le
1
Ahh, ajouter browserify à ma recherche sur Google m'a apporté la réponse, merci.
jason le
10
FWIW, notez que le message d'erreur n'indique pas que vous avez besoin de require.js. Babel convertit les modules en CommonJS par défaut, ce que Node utilise et qui définit une requirefonction (encore une fois, rien à voir avec require.js). Cependant, vous pouvez dire à Babel de convertir les modules en autre chose , par exemple AMD ou UMD, qui fonctionnerait alors avec require.js. Dans tous les cas, vous avez besoin d'un système pour charger les modules dans le navigateur, car le navigateur n'en fournit pas (encore) par défaut.
Felix Kling

Réponses:

136

Ai-je besoin de js lorsque j'utilise babel?

Vous aurez peut-être besoin d'un chargeur de module, mais ce n'est pas nécessaire RequireJS. Vous avez plusieurs options. Ce qui suit vous aidera à démarrer.


rollup.js avec rollup-plugin-babel

Rollup est un bundler de modules JavaScript de nouvelle génération. Il comprend nativement les modules ES2015 et produira un bundle qui ne nécessite aucun chargeur de module pour fonctionner. Les exportations inutilisées seront supprimées de la sortie, c'est ce qu'on appelle le tremblement d'arbre.

Maintenant, je recommande personnellement d'utiliser rollupjs, car il produit le résultat le plus clair et est facile à configurer, cependant, cela donne un aspect différent à la réponse. Toutes les autres approches font ce qui suit:

  1. Compilez le code ES6 avec babel, utilisez le format de module de votre choix
  2. Concaténez les modules compilés avec un chargeur de module OU utilisez un bundler qui parcourra les dépendances pour vous.

Avec rollupjs, les choses ne fonctionnent pas vraiment de cette façon. Ici, le rollup est la première étape, au lieu de babel. Il ne comprend que les modules ES6 par défaut. Vous devez donner un module d'entrée dont les dépendances seront parcourues et concaténées. Comme ES6 autorise plusieurs exportations nommées dans un module, rollupjs est suffisamment intelligent pour supprimer les exportations inutilisées, réduisant ainsi la taille du bundle. Malheureusement, l'analyseur rollupjs-s ne comprend pas la syntaxe> ES6, donc les modules ES7 doivent être compilés avant que le rollup ne les analyse, mais la compilation ne devrait pas affecter les importations ES6. Cela se fait en utilisant le rollup-plugin-babelplugin avec le babel-preset-es2015-rolluppreset (ce preset est le même que celui d'es2015, sauf le module transformer et le plugin external-helpers). Donc, le rollup fera ce qui suit avec vos modules s'il est correctement configuré:

  1. Lit votre module ES6-7 à partir du système de fichiers
  2. Le plugin babel le compile vers ES6 en mémoire
  3. rollup analyse le code ES6 pour les importations et les exportations (à l'aide de l'analyseur acorn, compilé en rollup)
  4. il parcourt tout le graphe et crée un seul bundle (qui peut encore avoir des dépendances externes, et les exportations de l'entrée peuvent être exportées, dans un format de votre choix)

Exemple de build 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));

Exemple de construction de grunt avec 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"]
        }
      }
    }
  });
}

Exemple de construction de gulp avec 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 a un package soigné appelé babelify . Son utilisation est simple et directe:

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

ou vous pouvez l'utiliser à partir de 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"));

Cela transpilera et concaténera votre code à la fois. Browserify .bundlecomprendra un joli petit chargeur CommonJS, et organisera vos modules transpilés en fonctions. Vous pouvez même avoir des importations relatives.

Exemple:

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

Pour compiler, exécutez simplement node build.jsdans la racine de votre projet.


Babel + WebPack

Compilez tout votre code en utilisant babel. Je vous recommande d'utiliser le transformateur de module amd (appelé babel-plugin-transform-es2015-modules-amddans babel 6). Après cela, regroupez vos sources compilées avec WebPack.

WebPack 2 est sorti! Il comprend les modules ES6 natifs et effectuera (ou plutôt simulera) le tremblement d'arbres en utilisant l' élimination intégrée du code mort de babili -s. Pour l'instant (septembre 2016), je suggérerais toujours d'utiliser le rollup avec babel, bien que mon opinion puisse changer avec la première version de WebPack 2. N'hésitez pas à discuter de vos opinions dans les commentaires.


Pipeline de compilation personnalisé

Parfois, vous souhaitez avoir plus de contrôle sur le processus de compilation. Vous pouvez implémenter votre propre pipeline comme ceci:

Tout d'abord, vous devez configurer babel pour utiliser les modules amd. Par défaut, babel transpile en modules CommonJS, ce qui est un peu compliqué à gérer dans le navigateur, bien que browserify parvienne à les gérer de manière agréable.

  • Babel 5: utiliser l' { modules: 'amdStrict', ... }option
  • Babel 6: utilisez le es2015-modules-amdplugin

N'oubliez pas d'activer l' moduleIds: trueoption.

Vérifiez le code transpilé pour les noms de modules générés, il y a souvent des incohérences entre les modules définis et requis. Voir sourceRoot et moduleRoot .

Enfin, vous devez avoir une sorte de chargeur de module, mais ce n'est pas nécessaire. Il y a des amandes , une minuscule cale qui fonctionne bien. Vous pouvez même implémenter le vôtre:

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

À la fin, vous pouvez simplement concaténer le shim du chargeur et les modules compilés ensemble, et exécuter un uglify sur cela.


Le code standard de Babel est dupliqué dans chaque module

Par défaut, la plupart des méthodes ci-dessus compilent chaque module avec babel individuellement, puis les concaténent ensemble. C'est ce que fait aussi babelify. Mais si vous regardez le code compilé, vous voyez que babel insère beaucoup de passe-partout au début de chaque fichier, la plupart d'entre eux sont dupliqués dans tous les fichiers.

Pour éviter cela, vous pouvez utiliser le babel-plugin-transform-runtimeplugin.

Tamas Hegedus
la source
1
C'est tellement complet; Merci. Re: le passe-partout Babel en double par fichier - serait-il correct de supposer que gzip annulerait tout sauf cela?
iono
1
Je ne l'ai jamais mesuré moi-même, mais je suppose que l'on réduirait le bundle avant la distribution, et que la minification trouverait probablement des noms différents pour les habitants, donc ils ne seront pas exactement les mêmes. Gzip devrait trouver les parties communes (résultant en un bon taux de compression), mais le navigateur doit toujours les analyser individuellement. En fin de compte, cela ne devrait pas être une surcharge notable, mais il y aura des gens comme moi qui n'aiment tout simplement pas le code dupliqué.
Tamas Hegedus
Assez juste, merci pour la réponse. Cela aurait probablement beaucoup de sens, également, dans les cas où vous deviez sauvegarder ou suivre le code de sortie dans le contrôle de version (où la taille du fichier non compressé se multiplie) ou lorsque vous souhaitez que la sortie ne soit pas réduite pour une raison quelconque.
iono
gulp-rollup pourrait également être un bon ajout à cette liste
GGG
@GGG Ajout d'un exemple de gulp. Malheureusement aucun des exemples ne fonctionne pour le moment sur windows, voir l'explication en haut des codes.
Tamas Hegedus
8

barebones webpack 2

1) S'il s'agit de votre répertoire racine:

index.html

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

scripts.js

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

formes.js

export class Circle {
  ...
}

2) ont installé noeud noeud

3) exécutez la commande suivante dans votre terminal:

$ npm install -g webpack

5) dans votre répertoire racine, exécutez ce qui suit:

$ webpack scripts.js bundle.js

Vous devriez maintenant avoir un fichier appelé bundle.js dans votre répertoire racine qui sera le fichier que votre index.html consommera. Il s'agit d'une fonctionnalité de regroupement minimaliste de webpack. Vous pouvez en savoir plus ici

Isaac Pak
la source
4

requiren'existe pas dans le navigateur, cette erreur est donc attendue. Vous devez utiliser quelque chose comme require.js ou Browserify.

Djechlin
la source