Ho bisogno di require js quando uso babel?


98

Sto sperimentando con ES6 e sto usando gulp per costruire e babel per transpile in ES5. L'output non viene eseguito nel nodo, ma solo collegato a da un file .htm con un tag. Sto pensando di dover aggiungere

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

o qualcosa di simile.

Sto cercando di importare / esportare.

////////////////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'errore è

Uncaught ReferenceError: require is not defined

Si riferisce a questo (dopo .pipe (babel ()) in gulp)

var _shapes = require('shapes');

3
Sì, perché requirenon esiste nel browser, è necessario utilizzare alcuni strumenti di compilazione come Require.js, Browserify o Webpack.
Jordan Running

1
Ahh, l'aggiunta di browserify al mio googling mi ha dato la risposta, grazie.
jason

10
FWIW, nota che il messaggio di errore non indica che hai bisogno di require.js. Babel converte i moduli in CommonJS per impostazione predefinita, che è ciò che utilizza Node e che definisce una requirefunzione (di nuovo, niente a che fare con require.js). Tuttavia, puoi dire a Babel di convertire i moduli in qualcos'altro , ad esempio AMD o UMD, che poi funzionerebbe con require.js. In ogni caso, è necessario un sistema per caricare i moduli nel browser, perché il browser non ne fornisce uno di default (ancora).
Felix Kling

Risposte:


136

Ho bisogno di require js quando uso babel?

Potrebbe essere necessario un caricatore di moduli, ma non è necessario RequireJS. Hai diverse opzioni. Quanto segue ti aiuterà a iniziare.


rollup.js con rollup-plugin-babel

Rollup è un bundler di moduli JavaScript di nuova generazione. Comprende i moduli ES2015 in modo nativo e produrrà un bundle che non necessita di alcun caricatore di moduli per funzionare. Le esportazioni inutilizzate verranno tagliate dall'output, si chiama scuotimento degli alberi.

Ora personalmente consiglio di utilizzare rollupjs, poiché produce l'output più chiaro ed è facile da configurare, tuttavia fornisce un aspetto diverso alla risposta. Tutti gli altri approcci fanno quanto segue:

  1. Compila il codice ES6 con babel, usa il formato del modulo che preferisci
  2. Concatena i moduli compilati insieme a un caricatore di moduli O usa un bundler che attraverserà le dipendenze per te.

Con rollupjs le cose non funzionano davvero in questo modo. Qui, il rollup è il primo passo, invece di Babel. Capisce solo i moduli ES6 per impostazione predefinita. È necessario fornire un modulo di ingresso di cui verranno attraversate e concatenate le dipendenze. Poiché ES6 consente più esportazioni con nome in un modulo, rollupjs è abbastanza intelligente da eliminare le esportazioni inutilizzate, riducendo così le dimensioni del pacchetto. Sfortunatamente il parser di rollupjs-s non comprende la sintassi> ES6, quindi i moduli ES7 devono essere compilati prima che il rollup li analizzi, ma la compilazione non dovrebbe influenzare le importazioni di ES6. Si fa utilizzando il rollup-plugin-babelplugin con il babel-preset-es2015-rolluppreset (questo preset è lo stesso di quello es2015, tranne il trasformatore del modulo e il plugin per aiutanti esterni). Quindi il rollup farà quanto segue con i tuoi moduli se impostato correttamente:

  1. Legge il tuo modulo ES6-7 dal filesystem
  2. Il plugin babel lo compila in ES6 in memoria
  3. rollup analizza il codice ES6 per importazioni ed esportazioni (utilizzando il parser di ghiande, compilato in rollup)
  4. attraversa l'intero grafico e crea un singolo bundle (che potrebbe ancora avere dipendenze esterne e le esportazioni della voce potrebbero essere esportate, in un formato a tua scelta)

Esempio di 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));

Esempio di build di grugnito con grugnito-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"]
        }
      }
    }
  });
}

Esempio di build gulp con 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 ha un bel pacchetto chiamato babelify . Il suo utilizzo è semplice e diretto:

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

oppure puoi usarlo da 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"));

Questo transpile e concatenerà il tuo codice in una volta. Browserify .bundleincluderà un simpatico caricatore CommonJS e organizzerà i tuoi moduli trasferiti in funzioni. Puoi anche avere importazioni relative.

Esempio:

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

Per compilare basta eseguire node build.jsnella root del progetto.


Babel + WebPack

Compila tutto il tuo codice usando babel. Ti consiglio di utilizzare il trasformatore del modulo amd (chiamato babel-plugin-transform-es2015-modules-amdin babel 6). Dopo di che raggruppa i tuoi sorgenti compilati con WebPack.

WebPack 2 è disponibile! Comprende i moduli ES6 nativi ed eseguirà (o meglio simulerà) lo shaking dell'albero usando l' eliminazione del codice morto incorporata babili -s. Per ora (settembre 2016) suggerirei ancora di utilizzare il rollup con babel, anche se la mia opinione potrebbe cambiare con la prima versione di WebPack 2. Sentiti libero di discutere le tue opinioni nei commenti.


Pipeline di compilazione personalizzata

A volte vuoi avere un maggiore controllo sul processo di compilazione. Puoi implementare la tua pipeline in questo modo:

Per prima cosa, devi configurare babel per usare i moduli amd. Per impostazione predefinita, babel esegue il transpiles nei moduli CommonJS, che è un po 'complicato da gestire nel browser, sebbene browserify riesca a gestirli in modo carino.

  • Babel 5: usa l' { modules: 'amdStrict', ... }opzione
  • Babel 6: usa il es2015-modules-amdplugin

Non dimenticare di attivare l' moduleIds: trueopzione.

Controllare il codice traspilato per i nomi dei moduli generati, ci sono spesso discrepanze tra i moduli definiti e quelli richiesti. Vedere sourceRoot e moduleRoot .

Infine, devi avere una sorta di caricatore di moduli, ma non è necessario requirejs. C'è almondjs , uno spessore minuscolo che funziona bene. Puoi persino implementare il tuo:

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

Alla fine, puoi semplicemente concatenare lo shim del caricatore ei moduli compilati insieme, ed eseguire un uglify su quello.


Il codice boilerplate di Babel è duplicato in ogni modulo

Per impostazione predefinita, la maggior parte dei metodi precedenti compila ogni modulo con babel individualmente, e poi li concatena insieme. Questo è ciò che fa anche babelify. Ma se guardi il codice compilato, vedi che babel inserisce molti boilerplate all'inizio di ogni file, la maggior parte di essi sono duplicati in tutti i file.

Per evitare ciò è possibile utilizzare il babel-plugin-transform-runtimeplugin.


1
Questo è così maledettamente completo; grazie. Ri: il boilerplate di Babel duplicato per file - sarebbe corretto presumere che gzip lo negherebbe del tutto?
iono

1
Non l'ho mai misurato da solo, ma presumo che si minificherebbe il pacchetto prima della distribuzione, e la minificazione probabilmente troverà nomi diversi per i locali, quindi non saranno esattamente gli stessi. Gzip dovrebbe trovare le parti comuni (risultando in un buon rapporto di compressione), ma il browser deve comunque analizzarle singolarmente. In definitiva non dovrebbe essere un sovraccarico evidente, ma ci saranno persone come me a cui semplicemente non piace il codice duplicato.
Tamas Hegedus

Abbastanza giusto, grazie per la risposta. Probabilmente avrebbe molto senso, anche, nei casi in cui è necessario eseguire il backup o tenere traccia del codice di output nel controllo della versione (dove la dimensione del file non compresso si moltiplica) o in cui si desidera che l'output non venga minimizzato per qualsiasi motivo.
iono

gulp-rollup potrebbe essere anche una buona aggiunta a questo elenco
GGG

@GGG Aggiunto esempio di gulp. Purtroppo nessuno degli esempi funziona al momento su Windows, vedi la spiegazione in alto i codici.
Tamas Hegedus

8

pacchetto web barebone 2

1) Se questa è la tua directory principale:

index.html

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

scripts.js

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

shape.js

export class Circle {
  ...
}

2) avere il nodo installato nodo

3) esegui il seguente comando nel tuo terminale:

$ npm install -g webpack

5) nella directory principale eseguire quanto segue:

$ webpack scripts.js bundle.js

Ora dovresti avere un file chiamato bundle.js nella tua directory principale che sarà il file che il tuo index.html consumerà. Questa è una funzione di raggruppamento minimalista di webpack. Puoi saperne di più qui


4

requirenon esiste nel browser, quindi è previsto questo errore. Devi usare qualcosa come require.js o Browserify.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.