В курсе рубрики студент упомянул очень интересный вопрос: «Я не устанавливал 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 реализована в Терсере.
Если вы хотите узнать больше о вебпаке и фронтенд-инжиниринге, вы можете отсканировать код и обратить внимание на паблик наших тиммейтов: частота ранних пушей — одна статья в неделю.