Почему webpack4 по умолчанию поддерживает сжатие синтаксиса ES6?

Webpack

В курсе рубрики студент упомянул очень интересный вопрос: «Я не устанавливал babel, я написал стрелочную функцию в записи js, и после запуска команды сборки webpack она была успешно скомпилирована. Почему это?». Сегодня я предлагаю вам вместе обсудить эту тему.

При использовании WebPack очень распространенным средством построения оптимизации являетсяМинимизировать цель сборки. Например, на этапе сборки создается только код модуля в src, а сторонний пакет, представленный в node_modules, не собирается.

проблема найдена

Если вы используете webpack 3.x и пишете такой скрипт сборки, мы можем избежать длительной сборки, вызванной разбором модулей в node_modules, установив поле exclude в загрузчике:

const path = require('path');
const webpack = require('webpack');

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: 'happypack/loader',
                exclude: path.join(__dirname, 'node_modules')
            }
        ]
    }
    plugins: [
        new webpack.optimize.UglifyJsPlugin()
    ]
};

Мы часто сталкиваемся с проблемой, если качество импортируемого npm-пакета недостаточно высокое, например, в node_modules есть синтаксис ES6, то webpack сообщит об ошибке на этапе uglify! Ниже приведены два распространенных сценария ошибок:

Строки шаблона для ES6

Предполагая, что в node_modules есть синтаксис строки шаблона ES6, UglifyJs выдаст ошибку на этапе сжатия кода производственного пакета.

图片

Стрелочные функции в ES6

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

图片

Осторожно, вы обнаружите, что если вы используете webpack 4, проблема, описанная в этом сценарии, больше не будет появляться.. Webpack 4 по умолчанию поддерживает сжатие кода ES6, в чем причина этого?

первоначальный анализ

Если вы проанализировали зависимости, например, webpack 4, проверьте файл package.json напрямую или передайтеnpm.broofa.com/Анализ графа зависимостей Webpack на сайте. Нетрудно обнаружить, что webpack 4 используется вterser-webpack-pluginПлагин заменяет uglifyjs-webpack-plugin, который раньше использовался в качестве встроенного плагина.

Взяв в качестве примера версию 4.39.3, вы можете увидеть, что зависимости ее файла package.json включают terser-webpack-plugin.

图片

Далее мы проанализировали и обнаружили, что версия веб-пакета 4.26.0 имеет отправку, и ее отправка является переключением на встроенный плагин веб-пакета.

图片

После такого анализа мы можем понять, что причина, по которой webpack 4 имеет возможность сжимать код ES6 по умолчанию, неотделима отterser-webpack-pluginРоль сыграна!

дальнейший анализ

Прежде чем исследовать принцип работы плагина terser-webpack-plugin, давайте систематически рассмотрим историю плагина сжатия кода:

  • Когда версия uglifyjs-webpack-plugin меньше v1.0, используется зависимость uglify-js.
  • Но uglify-js не поддерживает ES6, поэтому разветвите uglify-es в ветке гармонии репозитория uglify-js.
  • v1.x uglifyjs-webpack-plugin переключает зависимость uglify-js на uglify-es для поддержки синтаксиса сжатия ES6.
  • Но uglify-es больше не поддерживается: mishoo/UglifyJS2#3156 (комментарий)
  • Остановка обслуживания uglify-es вызвала разветвление terser, и terser обработал PR, которые не были объединены, и, наконец, создал отдельный репозиторий:GitHub.com/FiatO Сантос…
  • Впоследствии был создан terser-webpack-plugin, который основан на terser и имеет эквивалентную функциональность uglifyjs-webpack-plugin:GitHub.com/Webpack-con…
  • Поскольку uglifyjs-webpack-plugin v2.x возвращается к uglify-js, ES6 больше не поддерживается. Поэтому те проекты, которые хотят поддерживать сжатие синтаксиса ES6, должны переключиться на terser-webpack-plugin.

Примечание: источник истории плагина сжатияGitHub.com/Webpack/Веб…

На данный момент мы можем сделать основной вывод: terser-webpack-plugin основан на terser, поэтому он имеет возможности сжатия ES6, версия uglifyjs-webpack-plugin v2.x основана на uglify-js и не поддерживает сжатие ES6.

плагин полагаться Поддерживать ли ES6 (да/нет)
terser-webpack-plugin terser Y
uglifyjs-webpack-plugin v1.x uglify-es Y
uglifyjs-webpack-plugin v2.x uglify-js N

Принципиальный запрос

Принцип сжатия кода на самом деле довольно прост, и это также классический случай применения AST. Его процесс сжатия обычно:

     JS 源代码 -> AST -> 美化、压缩 -> 新的 AST -> 压缩后的代码 

После понимания основного процесса сжатия кода давайте взглянем на то, что содержит исходный код.Поскольку terser модифицирован из uglify-es Fork, его структура кода в основном такая же, как у uglify-js, за исключением того, что terser использует возможности статического анализа для Модули ES6. Разберем исходный код terser на примере:

  • ast.js: Описание абстрактного синтаксического дерева JS.
  • parse.js: парсер для разбора AST из исходного кода JS.
  • minify.js: для оптимизации AST в более короткую структуру
  • output.js: генератор кода, вывод сжатого кода из AST, поддержка генерации исходной карты
  • propmangle.js: сжатие длины переменной, обычно одного символа.
  • Scope.js: анализирует информацию об определении/ссылочном местоположении переменной.
  • transform.js: обход узла

Затем давайте рассмотрим различия между terser и uglify-js. После сравнения выясняется, что большая разница в том, что поддержка AST отличается.

Анализируя различия AST, выясняется, что нижеследующее является сравнением различий двух файлов только в более кратком виде, и они как раз соответствуют синтаксису ES6.

AST_Arrow,
AST_Await,
AST_BigInt,
AST_Class,
AST_ClassExpression,
AST_ConciseMethod,
AST_Const,
AST_DefaultAssign,
AST_Destructuring,
AST_Expansion,
AST_Export,
AST_ForOf,
AST_Import,
AST_Let,
AST_NameMapping,
AST_NewTarget,
AST_PrefixedTemplateString,
AST_Super,
AST_SymbolMethod,
AST_TemplateSegment,
AST_TemplateString,
AST_Yield

На данный момент мы обнаружили, что ключ к сжатию webpack4 ES6 поддерживается по умолчанию:AST Разборка грамматики ES6 реализована в Терсере.


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