Чи потрібно мені вимагати js, коли я використовую babel?


98

Я експериментую з ES6, а Im використовує глоток для побудови та 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

Посилається на це (після .pipe (babel ()) залпом)

var _shapes = require('shapes');

3
Так, оскільки requireв браузері не існує, вам потрібно використовувати якийсь інструмент побудови, такий як Require.js, Browserify або Webpack.
Йорданія, що біжить

1
Ах, додавши browserify до мого гуглінгу, я отримав відповідь, дякую.
jason

10
FWIW, зверніть увагу, що повідомлення про помилку не означає, що вам потрібен require.js. Babel перетворює модулі на CommonJS за замовчуванням, що використовує Node і визначає requireфункцію (знову ж таки, нічого спільного з require.js). Однак ви можете сказати Babel перетворити модулі на щось інше , наприклад, AMD або UMD, які потім працюватимуть з require.js. У будь-якому випадку вам потрібна система для завантаження модулів у браузер, оскільки браузер за замовчуванням не надає такого (поки).
Фелікс Клінг,

Відповіді:


136

Чи потрібно мені вимагати js, коли я використовую babel?

Вам може знадобитися якийсь завантажувач модулів, але це не обов'язково RequireJS. У вас є кілька варіантів. Наступне допоможе вам розпочати роботу.


rollup.js із зведеним плагіном-babel

Rollup - це пакет модулів JavaScript наступного покоління. Він чудово розуміє модулі ES2015 і створить пакет, для роботи якого не потрібен завантажувач модулів. Невикористаний експорт буде обрізаний з випуску, це називається похитуванням дерев.

Зараз я особисто рекомендую використовувати rollupjs, оскільки він дає найбільш чіткий результат і простий у налаштуванні, однак він надає інший аспект відповіді. Усі інші підходи роблять наступне:

  1. Складіть код ES6 за допомогою Babel, використовуйте формат модуля на ваш вибір
  2. Об’єднайте скомпільовані модулі разом із завантажувачем модулів АБО використовуйте пакет, який пройде залежності для вас.

З rollupjs все не так працює. Тут зведення - це перший крок, а не бабель. Він за замовчуванням розуміє лише модулі ES6. Ви повинні вказати модуль введення, залежності якого будуть обходити та об'єднувати. Оскільки ES6 дозволяє багаторазово експортувати імена в модулі, rollupjs досить розумний, щоб позбавити невикористаного експорту, тим самим зменшуючи розмір пакета. На жаль, аналізатор rollupjs-s не розуміє> синтаксис ES6, тому модулі ES7 повинні бути скомпільовані перед тим, як збірний аналізує їх, але компіляція не повинна впливати на імпорт ES6. Це робиться за допомогою rollup-plugin-babelплагіна з babel-preset-es2015-rollupпресетом (цей пресет є таким же, як і у es2015, за винятком модульного трансформатора та плагіна зовнішніх помічників). Тож зведене виконає з вашими модулями наступне, якщо правильно налаштовано:

  1. Зчитує ваш модуль ES6-7 із файлової системи
  2. Плагін babel компілює його до ES6 в пам’яті
  3. зведений аналізує код ES6 для імпорту та експорту (за допомогою аналізатора жолудів, зведеного в зведений)
  4. він обводить весь графік і створює єдиний пакет (який все ще може мати зовнішні залежності, а експортування запису може бути експортовано у форматі на ваш вибір)

Приклад побудови 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));

Приклад грунтової побудови за допомогою грубого зведення

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

Приклад складання ковтка за допомогою глотка

// 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 має акуратний пакет під назвою 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's.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 р.) Я все-таки пропоную використовувати зведення з babel, хоча моя думка може змінитися з першим випуском WebPack 2. Не соромтеся обговорювати свої думки в коментарях.


Спеціальний конвеєр компіляції

Іноді ви хочете мати більше контролю над процесом компіляції. Ви можете реалізувати свій власний конвеєр таким чином:

По-перше, вам потрібно налаштувати babel для використання модулів amd. За замовчуванням babel транспілює до модулів CommonJS, що трохи складно обробляти в браузері, хоча browserify вдається обробляти їх приємно.

  • Бабель 5: { modules: 'amdStrict', ... }варіант використання
  • Babel 6: використовуйте es2015-modules-amdплагін

Не забудьте увімкнути moduleIds: true опцію.

Перевірте перекладений код на наявність сформованих імен модулів, часто виникають невідповідності між визначеними та необхідними модулями. Див. SourceRoot та moduleRoot .

Нарешті, ви повинні мати якийсь модуль завантажувача, але це не обов’язково requirejs. Є мигдаль , крихітна прокладка, яка добре працює. Ви навіть можете реалізувати власні:

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

Врешті-решт, ви можете просто об'єднати прошивку завантажувача та скомпільовані модулі разом, і запустити uglify на цьому.


Зразковий код Babel продублюється в кожному модулі

За замовчуванням більшість з вищезазначених методів компілюють кожен модуль за допомогою babel окремо, а потім об'єднують їх разом. Це те, що робить і babelify. Але якщо ви подивитеся на скомпільований код, то побачите, що babel вставляє багато шаблонів на початку кожного файлу, більшість з них дублюються у всіх файлах.

Щоб запобігти цьому, ви можете використовувати babel-plugin-transform-runtimeплагін.


1
Це так криваво ретельно; спасибі. Re: дублікат зразка Babel на файл - чи правильно було б припустити, що gzip це все, крім заперечення?
iono

1
Я ніколи не вимірював його сам, але я припускав би, що до мінімуму можна було б зменшити пакет, і мініфікація, ймовірно, знайде різні назви для місцевих жителів, тож вони не будуть абсолютно однаковими. Gzip повинен знайти загальні частини (що призводить до хорошого ступеня стиснення), але браузер все одно повинен проаналізувати їх окремо. Зрештою, це не повинно бути помітним накладним витратам, але знайдуться такі люди, як я, яким просто не подобається дубльований код.
Тамаш Гегедус

Досить справедливо, дякую за відповідь. Можливо, це мало б багато сенсу також у випадках, коли вам довелося створити резервну копію або відслідковувати вихідний код у контролі версій (де розмір нестисненого файлу збільшується) або де ви хочете, щоб вихідний результат не був усунутий з будь-якої причини.
iono

gulp-rollup також може бути гарним доповненням до цього списку
GGG

@GGG Додано приклад ковтка. На жаль, на даний момент жоден із прикладів не працює на вікнах, див. Пояснення вгорі кодів.
Тамаш Гегедус,

8

веб-пакет без голови 2

1) Якщо це ваш кореневий каталог:

index.html

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.