Бабел в конце как настроить?

Node.js Командная строка JavaScript Babel

задний план

Говоря о ES6, webpack, упаковка и модульность всегда неотделимы от babel, который широко использовался в качестве компилятора js. в вавилонеОфициальный сайтВот как это вводится:

Babel is a JavaScript compiler.

Use next generation JavaScript, today.

Всем известно, что js, как основной язык, очень зависит от среды выполнения (браузер, узел и т. д.), и разные среды по-разному поддерживают синтаксис js, особенно после ES6, обновление версии ECMAScrip достигло ритма раз в год, Хотя ежегодное обновление невелико, предложений много каждый год. Появление babel призвано решить эту проблему, перевести код, написанный с использованием нового стандарта, в код, который можно запустить в текущей среде, проще говоря, перевести (перекодировать + скомпилировать) код ES6 в ES5.

Часто люди не понимают, что делает babel, когда они используют babel.Они знают только, что для написания ES6 им нужно внедрить babel-загрузчик в webpack, а затем случайным образом скопировать .babelrc онлайн в каталог проекта для запуска (ps: Собственно я о себе). Очень важно понимать конфигурацию babel, что позволяет избежать некоторых ненужных ям, таких как: использование Object.assign в коде сообщит об ошибке в некоторых младших версиях браузеров, думая, что есть проблема с упаковкой webpack, но на самом деле это проблема конфигурации Babel.

ES6

Перед текстом поговорим об ES6, ES этоECMAScript, 6 означает шестую версию (также известную как ES2015, потому что она была выпущена в 2015 году), которая является стандартом реализации javascript.

Грамматика, включенная в стандарт ES, должна пройти следующие пять этапов:

  1. Stage 0: strawman
  2. Stage 1: proposal
  3. Этап 2: черновик - должен содержать2 экспериментальные бетонные реализации, один из которых можно реализовать с помощью транспилятора, например Babel.
  4. Этап 3: кандидат - не менее2 конкретные реализации, соответствующие спецификации.
  5. Stage 4: finished

Можно видеть, что предложение было реализовано в некоторых средах, когда оно вошло в стадию stage3, а babel был реализован на стадии stage2. Следовательно, синтаксис, который был включен в стандарт ES, уже реализован в большинстве сред, так зачем использовать babel для перевода, потому что нельзя гарантировать, что каждая среда, в которой работает код, является самой последней версией и реализует спецификацию.

Для получения дополнительной информации о ES6, пожалуйста, обратитесь к hax live:Hax: Как изучить и попрактиковаться в ES201X?

Изменения версии Babel

На момент написания этой статьи появилась версия Babel.v7.0.0-beta.3То есть выйдет официальная версия 7.0, что радует. Но сегодня я не говорю о 7.0, просто говорю о Babel6, Babel достиг версии 6, когда я знаю и начинаю использовать Babel, я не переживал возраст 5.

В эпоху babel5, babel относится к типу ведер всего семейства, пока Babel установлен, все инструменты, связанные с babel, будут установлены. Готов использовать.

Но в babel6 были внесены следующие изменения:

  • Удалите установку корзины семейства babel и разделите ее на отдельные модули, такие как: babel-core, babel-cli, babel-node, babel-polyfill и т. д.;

Вы можете увидеть, какие модули в настоящее время есть у Babel, в репозитории Babel на github.babel-package

  • Добавлен файл конфигурации .babelrc, в основном все переводы babel будут читать эту конфигурацию;
  • Добавлена ​​конфигурация плагина, все плагины, любой код для перевода можно свободно настроить в плагине;
  • Добавлена ​​предустановленная конфигурация, babel5 будет переводить синтаксис ES6 и jsx по умолчанию, а синтаксис, переведенный babel6, должен быть настроен в perset, предустановка — это просто использование серии пакетов плагинов.

Знакомство с каждым модулем Babel

Babel 6 разбивает семейство Babel на множество различных модулей, и только зная, как использовать эти модули, мы можем лучше понять Babel.

Некоторый пример кода ниже был загружен наgithub, добро пожаловать в гости, добро пожаловать в звезду.

Способ установки:

#通过npm安装
npm install babel-core babel-cli babel-node

#通过yarn安装
yarn add babel-core babel-cli babel-node

1,babel-core

Как видно из названия, babel-core существует как ядро ​​Babel, а ядро ​​API Babel находится в этом модуле, например: transform.

Вот несколько API в babel-core

  • babel.transform: используется для транскодирования строк для получения AST
/*
 * @param {string} code 要转译的代码字符串
 * @param {object} options 可选,配置项
 * @return {object} 
*/
babel.transform(code: string, options?: Object)
    
//返回一个对象(主要包括三个部分):
{
    generated code, //生成码
    sources map, //源映射
    AST  //即abstract syntax tree,抽象语法树
}

Дополнительную информацию об АСТ см.здесь.

Некоторые инструменты упаковки или сборки, использующие плагин babel, используют этот метод. Вот некоторые исходные коды, импортированные в плагин babel:

//gulp-babel
const babel = require('babel-core');
/*
some codes...
*/
module.exports = function (opts) {
    opts = opts || {};
	return through.obj(function (file, enc, cb) {
        try {
            const fileOpts = Object.assign({}, opts, {
            	filename: file.path,
            	filenameRelative: file.relative,
            	sourceMap: Boolean(file.sourceMap),
            	sourceFileName: file.relative,
            	sourceMapTarget: file.relative
            });
            const res = babel.transform(file.contents.toString(), fileOpts);
            if (res !== null) {
            	//some codes
            }
        } catch (err) {
            //some codes
        }
    }
}

//babel-loader
var babel = require("babel-core");
/*
some codes...
*/
var transpile = function transpile(source, options) {
    //some code
    try {
        result = babel.transform(source, options);
    } catch (error) {
        //some codes
    }
    //some codes
}

//rollup-pugin-babel
import { buildExternalHelpers, transform } from 'babel-core';
/*
some codes...
*/
export default function babel ( options ) {
    //some codes
    return {
        // some methods
        transform ( code, id ) {
            const transformed = transform( code, localOpts );
            //some codes
            return {
            	code: transformed.code,
            	map: transformed.map
            };
        }
    }
}

Выше приведен некоторый исходный код, когда некоторые инструменты упаковки вводят подключаемый модуль babel.Вы можете видеть, что код в основном перекодируется, сначала вызывая метод преобразования.

  • babel.transformFile
//异步的文件转码方式,回调函数中的result与transform返回的对象一至。
babel.transformFile("filename.js", options, function (err, result) {
  result; // => { code, map, ast }
});
  • babel.transformFileSync
//同步的文件转码方式,返回结果与transform返回的对象一至。
babel.transformFileSync(filename, options) // => { code, map, ast }
  • babel.transformFromAst
//将ast进行转译
const { code, map, ast } = babel.transformFromAst(ast, code, options);

2,babel-cli

babel-cli — это инструмент для экранирования js-файлов из командной строки.

Инструкции:

  • Вывод переведенного кода прямо в командную строку
    babel script.js
    
  • Укажите выходной файл
    babel script.js --out-file build.js
    或者是
    babel script.js -o build.js
    

Напишем код со стрелочной функцией:

//script.js
const array = [1,2,3].map((item, index) => item * 2);

Затем запустите babel script.js в командной строке и обнаружите, что выходной код, похоже, не переведен.

babel转译

Так как мы не указали Babel, какие типы нужно транслировать, давайте посмотрим, как указать стрелочные функции в коде трансляции.

babel --plugins transform-es2015-arrow-functions script.js

转译箭头函数

Или добавьте в каталог файл .babelrc со следующим содержимым:

{
    "plugins": [
        "transform-es2015-arrow-functions"
    ]
}

.babelrc — это глобальный файл конфигурации babel.Все операции babel (включая babel-core и babel-node) в основном будут читать эту конфигурацию, которая будет подробно описана позже.

3. вавилонский узел

Babel-node устанавливается вместе с babel-cli. Ввод babel-node в командной строке запустит REPL (Read-Eval-Print-Loop), который представляет собой среду выполнения js, поддерживающую ES6.

测试babel-node

Фактически, без babel-node, непосредственно под узлом, если версия узла выше 6, поддерживается большая часть синтаксиса ES6, и теперь версия узла достигла 8.7.0.

node环境箭头函数测试

babel-node также можно использовать для прямого выполнения js-скриптов, что аналогично прямому использованию команды node, за исключением того, что babel будет транслироваться в процессе выполнения, и babel официально не рекомендует использовать его напрямую в рабочей среде, потому что код, сгенерированный компиляцией babel в реальном времени, будет кэшироваться в памяти, использование памяти слишком велико, поэтому мы просто это понимаем.

babel-node script.js

4.babel-register

Это видно из буквального значения babel-register. Это регистр для babel. Он переписывает метод require узла внизу. После введения babel-register все требования имеют суффиксы .es6, .es, .jsx и .js Модули переведены Babel.

Также проведите эксперимент со стрелочными функциями:

//test.js
const name = 'shenfq';
module.exports = () => {
    const json = {name};
    return json;
};
//main.js
require('babel-register');
var test = require('./test.js');  //test.js中的es6语法将被转译成es5

console.log(test.toString()); //通过toString方法,看看控制台输出的函数是否被转译

register转译

По умолчанию babel-register игнорирует перевод модулей в каталоге node_modules.Если вы хотите включить его, вы можете настроить его следующим образом.

require("babel-register")({
  ignore: false
});

Babel-register и babel-core будут установлены одновременно, и в babel-core будет файл register.js, поэтому есть два способа внедрить babel-register:

require('babel-core/register');
require('babel-register');

Однако первый способ официально не рекомендуется, т.к. babel-register стал самостоятельным модулем, а в файле register.js babel-core есть следующие комментарии.

TODO: eventually deprecate this console.trace("use the babel-register package instead of babel-core/register");

5.babel-polyfill

Слово «полифилл» в переводе на китайский язык垫片Смысл, подробное объяснение в том, что ножки стола чуть короче с одной стороны, возьмите что-нибудь, чтобы расплющить стол. Роль полифилла в коде в основном заключается в использовании существующего синтаксиса и API для реализации некоторых API, которые еще не реализованы в браузерах, а также в исправлении некоторых дефектов браузера. Например, у Array есть новый метод include, который я хочу использовать, но он недоступен в более ранних версиях браузеров, поэтому мне приходится выполнять обработку совместимости:

if (!Array.prototype.includes) {
  Object.defineProperty(Array.prototype, 'includes', {
    value: function(searchElement, fromIndex) {
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }
      var o = Object(this);
      var len = o.length >>> 0;
      if (len === 0) {
        return false;
      }
      var n = fromIndex | 0;
      var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
      while (k < len) {
        if (o[k] === searchElement) {
          return true;
        }
        k++;
      }
      return false;
    }
  });
} 

Вышеупомянутое просто предоставляет полифилл для метода include, а код исходит изMDN.

Поняв значение полифилла, давайте поговорим о том, почему в Babel есть полифилл. Поскольку перевод Babel — это только перевод синтаксического уровня, такой как стрелочная функция, присваивание деструктурирования, класс, некоторые новые API и глобальные функции (такие как: Promise) не могут быть переведены, В настоящее время в код необходимо ввести babel-polyfill. сделать код идеальной поддержкой среды ES6+. Представленный ранее узел babel автоматически введет в код пакет babel-polyfill.

Метод импорта:

//在代码的最顶部进行require或者import

require("babel-polyfill");

import "babel-polyfill";

//如果使用webpack,也可以在文件入口数组引入
module.exports = {
  entry: ["babel-polyfill", "./app/js"]
};

Но часто мы не используем весь синтаксис ES6+, глобальное добавление всех прокладок определенно увеличит размер нашего кода, и позже мы представим другие способы добавления прокладок.

вавилонская конфигурация

Некоторые модули, обычно используемые Babel, были представлены ранее, давайте взглянем на конфигурационный файл babel..babelrc.

Следующий суффикс rc происходит от linux.После использования linux вы знаете, что в linux есть много файлов, оканчивающихся на rc, например.bashrc, рсrun commandАббревиатура , переведенная на китайский язык, означает команду во время выполнения, что означает, что файл будет вызываться при выполнении программы.

Все операции babel в основном будут читать этот файл конфигурации, за исключением некоторых параметров параметров, установленных в функции обратного вызова, если такого файла конфигурации нет, он будет прочитан изpackage.jsonКонфигурация считывается из свойств файла babel.

plugins

Давайте кратко представим плагины, плагины в Babel, Настраивая различные плагины, мы можем сказать Babel, какие части нашего кода нужно перевести.

Вот официальный сайт BabelСписок плагинов, который содержит все плагины, поддерживаемые в настоящее время Babel.

Например:

{
    "plugins": [
        "transform-es2015-arrow-functions", //转译箭头函数
        "transform-es2015-classes", //转译class语法
        "transform-es2015-spread", //转译数组解构
        "transform-es2015-for-of" //转译for-of
    ]
}
//如果要为某个插件添加配置项,按如下写法:
{
    "plugins":[
        //改为数组,第二个元素为配置项
        ["transform-es2015-arrow-functions", { "spec": true }]
    ]
}

Вышеупомянутое является просто переводом на уровне синтаксиса.Как упоминалось ранее, некоторые вещи на уровне API должны быть представлены с помощью полифиллов.Точно так же у Babel также есть ряд плагинов для их поддержки.

{
    "plugins":[
        //如果我们在代码中使用Object.assign方法,就用如下插件
        "transform-object-assign"
    ]
}

//写了一个使用Object.assign的代码如下:
const people = Object.assign({}, {
    name: 'shenfq'
});
//经过babel转译后如下:
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

const people = _extends({}, {
    name: 'shenfq'
});

Этот полифилл, добавленный через преобразование, будет введен только в текущий модуль. Представьте, что в фактической разработке есть несколько модулей, использующих один и тот же API. Каждый модуль вводит один и тот же полифил, и в проекте появляется много повторяющегося кода. Это должно быть своего рода катастрофа. Вводить трансформы, требующие полифиллов, по одной довольно проблематично, и нет гарантии, что введенные вручную трансформы будут правильными, решение будет предоставлено позже:transform-runtime.

В дополнение к добавлению полифилов, у Babel также есть вспомогательный инструментарий.Если у вас установлен babel-cli, вы можете вывести этот инструментарий напрямую с помощью следующей команды:

./node_modules/.bin/babel-external-helpers > helpers.js

Этот инструментарий подобен модулю utils в babel.Как и utils в нашем проекте, он будет использоваться во многих местах.Например, babel реализует Object.assign с помощью метода _extend в хелперах. Чтобы избежать многократного обращения к вспомогательным функциям Babel в одном и том же файле, передайтеexternal-helpersПлагин может извлекать эти вспомогательные функции в начало файла, чтобы избежать множественных ссылок.

//安装: cnpm install --save-dev babel-plugin-external-helpers

//配置
{
  "plugins": ["external-helpers"]
}

Хотя этот плагин может избежать множественных ссылок на вспомогательные функции в файле, он не может напрямую избежать повторяющихся ссылок в нескольких файлах.Это та же проблема, что и добавление полифилов через преобразование, как упоминалось выше.Эти ссылки находятся только на уровне модуля и упакованы с распространенность инструментов сегодня, необходимо рассмотреть, как уменьшить избыточность кода, вызванную тем, что несколько модулей неоднократно ссылаются на один и тот же код.

Конечно, вы также можете напрямую импортировать ранее сгенерированный вспомогательный файл вверху каждого js-файла, в котором необходимо использовать вспомогательные средства, и использовать инструмент упаковки для извлечения этого общего модуля.

require('helpers');

После разговора о помощниках Babel, это последний плагин в системе плагинов:transform-runtime. Этот плагин также упоминался ранее в transform-polyfill, Причина, по которой он помещен за хелперами, заключается в том, что этот плагин может автоматически добавлять полифиллы и хелперы в проект.

cnpm install -D babel-plugin-transform-runtime babel-runtime

Плагин transform-runtime зависит от babel-runtime, поэтому лучше всего установить babel-runtime при установке transform-runtime, чтобы предотвратить некоторые ненужные ошибки. babel-runtime состоит из трех частей:

  1. core-js

    core-js чрезвычайно мощный.Большинство прокладок ES5,6,7 реализованы через ES3.Автор zloirock-программист из семьи бойцов.Сам поддерживает core-js.Я слышал,что он до сих пор ищет работа недавно Выше приведен адрес github core-js, вы можете посмотреть, если вам интересно.

  2. regenerator

    regenerator — это библиотека из facebook, которая реализует функции генератора.

  3. helpers

    Некоторые инструментальные функции babel, да, этот хелпер — это то же самое, что и хелперы, сгенерированные babel-external-helpers

Это также видно из файла package.json среды выполнения babel, среда выполнения полагается на то, что есть.

babel-runtime的package.json

После запуска babel смонтированные помощники могут быть введены следующим образом:

require('babel-runtime/helpers');

Есть также некоторые элементы конфигурации при использовании среды выполнения:

{
    "plugins": [
        ["transform-runtime", {
            "helpers": false, //自动引入helpers
            "polyfill": false, //自动引入polyfill(core-js提供的polyfill)
            "regenerator": true, //自动引入regenerator
        }]
    ]
}

Сравните разницу между transform-runtime и babel-polyfill, вводящими прокладки:

  1. Среда выполнения импортируется по требованию. Какие полифиллы нужно использовать, и среда выполнения автоматически импортирует их для вас. Нет необходимости вручную настраивать плагины один за другим, но введенные полифиллы не являются глобальными и имеют некоторые ограничения. И полифилл, введенный средой выполнения, не будет переписывать некоторые методы экземпляра, такие как методы в цепочке прототипов Object и Array, как упоминалось выше.Array.protype.includes.
  2. Babel-polyfill может решить эти проблемы во время выполнения.Его прокладки глобальны и универсальны.По сути, все полифиллы, используемые в ES6, находятся в babel-polyfill, который обеспечивает полную среду ES6+. Babel официально рекомендует, пока вас не волнует объем babel-polyfill, лучше всего внедрять его глобально, потому что это самый безопасный способ.
  3. Общая рекомендация состоит в том, чтобы использовать babel-runtime, который не загрязняет глобальную область видимости, при разработке некоторых фреймворков или библиотек, а при разработке веб-приложений babel-polyfill можно внедрять глобально, чтобы избежать ненужных ошибок, а babel можно внедрять глобально в больших веб-приложениях. приложения -polyfill также может уменьшить размер ваших упакованных файлов (по сравнению с введением дубликатов полифиллов для каждого модуля).

presets

Такая конфигурация плагина явно будет очень хлопотной, для удобства Babel предоставляет нам элемент конфигурации, называемый persets (по умолчанию).

Пресет представляет собой набор из серии плагинов, как и ретушь.Некоторые параметры последней ретуши сохраняются как пресет, который можно использовать непосредственно в следующий раз.

Если вы хотите перевести синтаксис ES6, просто настройте его следующим образом:

//先安装ES6相关preset: cnpm install -D babel-preset-es2015
{
    "presets": ["es2015"]
}

//如果要转译的语法不止ES6,还有各个提案阶段的语法也想体验,可以按如下方式。
//安装需要的preset: cnpm install -D babel-preset-stage-0 babel-preset-stage-1 babel-preset-stage-2 babel-preset-stage-3
{
    "presets": [
        "es2015",
        "stage-0",
        "stage-1",
        "stage-2",
        "stage-3",
    ]
}

//同样babel也能直接转译jsx语法,通过引入react的预设
//cnpm install -D babel-preset-react
{
    "presets": [
        "es2015",
        "react"
    ]
}

Однако указанные выше пресеты официально больше не рекомендуются.Единственная рекомендацияпредустановка:babel-preset-env.

Этот пресет может гибко решать, какие плагины и полифиллы загружать, но он все равно должен быть настроен разработчиком вручную.

// cnpm install -D babel-preset -env
{
    "presets": [
        ["env", {
            "targets": { //指定要转译到哪个环境
                //浏览器环境
                "browsers": ["last 2 versions", "safari >= 7"],
                //node环境
                "node": "6.10", //"current"  使用当前版本的node
                
            },
             //是否将ES6的模块化语法转译成其他类型
             //参数:"amd" | "umd" | "systemjs" | "commonjs" | false,默认为'commonjs'
            "modules": 'commonjs',
            //是否进行debug操作,会在控制台打印出所有插件中的log,已经插件的版本
            "debug": false,
            //强制开启某些模块,默认为[]
            "include": ["transform-es2015-arrow-functions"],
            //禁用某些模块,默认为[]
            "exclude": ["transform-es2015-for-of"],
            //是否自动引入polyfill,开启此选项必须保证已经安装了babel-polyfill
            //参数:Boolean,默认为false.
            "useBuiltIns": false
        }]
    ]
}

О последнем параметреuseBuiltIns, следует отметить два момента:

  1. Если для useBuiltIns установлено значение true, в проект необходимо добавить babel-polyfill.
  2. Babel-polyfill можно ввести только один раз, и если его ввести несколько раз, это вызовет конфликты в глобальной области видимости.

Провел эксперимент, тот же код, только.babelrcОдин из конфигов включенuseBuiltIns, одного нет, разница в объеме между двумя файлами js 70К,ткни меня.

документ размер
useBuiltIns.js 189kb
notUseBuiltIns.js 259kb

Ссылаться на

  1. Повторит ли ECMAScript 6 ошибки ECMAScript 4?
  2. Вавилонское руководство
  3. официальный сайт Бабеля
  4. babel-preset-env: a preset that configures Babel for you

Moreover

Существует также полифилл, называемыйpolyfill.ioАртефакт, пока он представлен в браузере

CDN.poly fill.IO/V2/poly fill…

Сервер вернет соответствующий файл полифилла в соответствии с UserAgent браузера, что удивительно, можно сказать, что это самое элегантное решение проблемы чрезмерного полифилла.


На то, чтобы написать это до и после, у меня ушла почти неделя, и я проверил много информации (официальный сайт Babel и github читал ее несколько раз), и, наконец, я вышел.

Оригинальная ссылка