предисловие
Приближается 2020 год, среди множества требований к набору персонала,webpack,工程化Эти термины встречаются все чаще. В повседневной разработке мы часто используем такие вещи, какvue-cli,create-react-appСтроительные леса для нашего проекта. Но если вы хотите выделиться в коллективе (выделиться из толпы) и получить более выгодное предложение (погасить ипотеку), то вы должны иметь глубокое понимание людей, с которыми мы часто имеем делоwebpack
Эта статья разделена на три части для быстрого освоения webpack, на прочтение этой статьи уходит около 60 минут. Если есть какие-либо недостатки, пожалуйста, поправьте меня
Эта статья написана на основе
-
webpack 4.41.2Версия -
node: 10.15.3Версия
1 Начало работы (используйте эти небольшие примеры, чтобы ознакомиться с конфигурацией веб-пакета)
1.1 Инициализировать проект
Создайте новый каталог и инициализируйте npm
npm init
webpack работает в среде узла, нам нужно установить следующие два пакета npm
npm i -D webpack webpack-cli
- npm i -D — это сокращение от npm install --save-dev
- npm i -S — это сокращение от npm install --save
Создать новую папкуsrc, а затем создайте новый файлmain.js, напишите небольшой код для проверки
console.log('call me 老yuan')
Настройте команду package.json
npm run build
На этом этапе, если папка dist создана и содержит main.js внутри, это означает, что пакет был успешно выполнен.
1.2 Запуск собственной конфигурации
Простой пример выше - это просто собственная конфигурация веб-пакета по умолчанию, здесь мы должны получить более богатую пользовательскую конфигурацию.
создать новыйbuildпапку, создайте новуюwebpack.config.js
// webpack.config.js
const path = require('path');
module.exports = {
mode:'development', // 开发模式
entry: path.resolve(__dirname,'../src/main.js'), // 入口文件
output: {
filename: 'output.js', // 打包后的文件名称
path: path.resolve(__dirname,'../dist') // 打包后的目录
}
}
Изменить нашу команду упаковки
npm run buildВы обнаружите, что создаются следующие каталоги (изображения).в
distв папкеmain.jsэто файл, который нам нужно запустить в браузереКонечно, это не единственный случай практического применения, давайте проведем вас по быстрому запуску вебпака через практические кейсы.
1.3 Настройка HTML-шаблона
js запакованы, но мы не можемhtmlВручную импортируйте упакованные js в файл
Некоторые друзья здесь могут подумать, что имя нашего упакованного файла js не всегда фиксировано (output.js)? То есть вам не нужно каждый раз менять имя импортируемого файла? Фактически, мы часто настраиваем это в нашей повседневной разработке:
module.exports = {
// 省略其他配置
output: {
filename: '[name].[hash:8].js', // 打包后的文件名称
path: path.resolve(__dirname,'../dist') // 打包后的目录
}
}
генерируется в это времяdistФайлы каталога следующие
npm i -D html-webpack-plugin
создать новыйbuildродственная папкаpublic, создайте новый index.html внутри
Конкретные файлы конфигурации следующие
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode:'development', // 开发模式
entry: path.resolve(__dirname,'../src/main.js'), // 入口文件
output: {
filename: '[name].[hash:8].js', // 打包后的文件名称
path: path.resolve(__dirname,'../dist') // 打包后的目录
},
plugins:[
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'../public/index.html')
})
]
}
Сгенерированный каталог выглядит следующим образом (рисунок)
1.3.1 Как разрабатывать файлы с несколькими записями
Создайте несколько экземпляров html-webpack-plugin, чтобы решить эту проблему.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode:'development', // 开发模式
entry: {
main:path.resolve(__dirname,'../src/main.js'),
header:path.resolve(__dirname,'../src/header.js')
},
output: {
filename: '[name].[hash:8].js', // 打包后的文件名称
path: path.resolve(__dirname,'../dist') // 打包后的目录
},
plugins:[
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'../public/index.html'),
filename:'index.html',
chunks:['main'] // 与入口文件对应的模块名
}),
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'../public/header.html'),
filename:'header.html',
chunks:['header'] // 与入口文件对应的模块名
}),
]
}
На этом этапе вы обнаружите, что создается следующий каталог
1.3.2 clean-webpack-plugin
Каждый раз, когда вы выполняете сборку npm run, вы обнаружите, что последние упакованные файлы остаются в папке dist.Здесь мы рекомендуем плагин, который поможет нам очистить папку перед упаковкой и выводом.
clean-webpack-plugin
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
// ...省略其他配置
plugins:[new CleanWebpackPlugin()]
}
1.4 Цитирование CSS
Наш входной файл — js, поэтому мы вводим наш css-файл в запись js.
npm i -D style-loader css-loader
Если мы используем меньше стилей для создания, нам нужно установить еще два
npm i -D less less-loader
Файл конфигурации выглядит следующим образом
// webpack.config.js
module.exports = {
// ...省略其他配置
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader'] // 从右向左解析原则
},
{
test:/\.less$/,
use:['style-loader','css-loader','less-loader'] // 从右向左解析原则
}
]
}
}
браузер открытhtmlследующим образом
1.4.1 Добавить префикс браузера в css
npm i -D postcss-loader autoprefixer
Конфигурация выглядит следующим образом
// webpack.config.js
module.exports = {
module:{
rules:[
{
test:/\.less$/,
use:['style-loader','css-loader','postcss-loader','less-loader'] // 从右向左解析原则
}
]
}
}
Далее нам также необходимо представитьautoprefixerЧтобы сделать его эффективным, есть два способа
1. Создайте проект в корневом каталоге проектаpostcss.config.jsфайл, настроенный следующим образом:
module.exports = {
plugins: [require('autoprefixer')] // 引用该插件即可了
}
2, прямо вwebpack.config.jsконфигурация
// webpack.config.js
module.exports = {
//...省略其他配置
module:{
rules:[{
test:/\.less$/,
use:['style-loader','css-loader',{
loader:'postcss-loader',
options:{
plugins:[require('autoprefixer')]
}
},'less-loader'] // 从右向左解析原则
}]
}
}
В это время мы обнаружили, что CSS, добавленные в файл HTML в теге стиля, но если есть много стилей файлов, все добавляют в HTML, неизбежно, что это хаотично. В это время мы хотим использовать разделение CSS для введения файла CSS в форме внешней цепи. В это время нам нужно помочь нам с плагинами.
1.4.2 Разделить CSS
npm i -D mini-css-extract-plugin
До webpack 4.0 мы прошли
extract-text-webpack-pluginПлагин, который извлекает стили css из файлов js в отдельные файлы css. После webpack 4.0 официально рекомендуется использоватьmini-css-extract-pluginПлагин для упаковки css файлов
Файл конфигурации выглядит следующим образом
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
//...省略其他配置
module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
],
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].[hash].css",
chunkFilename: "[id].css",
})
]
}
1.4.3 Разделить несколько css
Здесь нужно сказать немного больше, вышеизложенное мы использовали
mini-css-extract-pluginВсе стили css будут объединены в один файл css. Если вы хотите разделить на несколько файлов css, соответствующих один к одному, нам нужно использоватьextract-text-webpack-plugin, в то время как в настоящее времяmini-css-extract-pluginЭта функция пока не поддерживается. Нам нужно установить @next версиюextract-text-webpack-plugin
npm i -D extract-text-webpack-plugin@next
// webpack.config.js
const path = require('path');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
let indexLess = new ExtractTextWebpackPlugin('index.less');
let indexCss = new ExtractTextWebpackPlugin('index.css');
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use: indexCss.extract({
use: ['css-loader']
})
},
{
test:/\.less$/,
use: indexLess.extract({
use: ['css-loader','less-loader']
})
}
]
},
plugins:[
indexLess,
indexCss
]
}
1.5 Упаковка картинок, шрифтов, мультимедиа и других файлов
file-loaderТо есть после некоторой обработки файла (в основном обработки имени файла и пути, анализа URL-адреса файла) и перемещения файла в выходной каталог.
url-loaderобычно сfile-loaderИспользуется в комбинации, работает как загрузчик файлов, если размер файла меньше предельного размера. вернет кодировку base64, в противном случае используйте загрузчик файлов для перемещения файла в выходной каталог
// webpack.config.js
module.exports = {
// 省略其它配置 ...
module: {
rules: [
// ...
{
test: /\.(jpe?g|png|gif)$/i, //图片文件
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, //媒体文件
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, // 字体
use: [
{
loader: 'url-loader',
options: {
limit: 10240,
fallback: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[hash:8].[ext]'
}
}
}
}
]
},
]
}
}
1.6 Экранирование js-файлов с помощью babel
Чтобы сделать наш код js совместимым с большим количеством сред, нам нужно установить зависимости
npm i -D babel-loader @babel/preset-env @babel/core
- Уведомление
babel-loaderа такжеbabel-coreверсия соответствует
-
babel-loader8.x соответствующийbabel-core7.x -
babel-loader7.х перепискаbabel-core6.x
Конфигурация выглядит следующим образом
// webpack.config.js
module.exports = {
// 省略其它配置 ...
module:{
rules:[
{
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env']
}
},
exclude:/node_modules/
},
]
}
}
надbabel-loaderСинтаксис ES6/7/8 будет преобразован только в синтаксис ES5, но новый API не конвертирует, например (Promise, Generator, SET, MAPS, Proxy и т. д.)
На этом этапе нам нужно использовать babel-polyfill, чтобы помочь нам преобразовать
npm i @babel/polyfill
// webpack.config.js
const path = require('path')
module.exports = {
entry: ["@babel/polyfill",path.resolve(__dirname,'../src/index.js')], // 入口文件
}
- Полезнее читать следующие статьи, вручную постукивая по демо выше.Студентам-новичкам рекомендуется постучать три раза и более.
[
Вышеупомянутая практика заключается в том, что у нас есть предварительное понимание функции вебпака, но для того, чтобы быть опытным в разработке, нам нужна система реального боя. Давайте избавимся от строительных лесов и попробуем создать среду разработки vue самостоятельно.
2 Создайте среду разработки vue
Приведенный выше небольшой пример помог, и мы реализовали упаковку css, изображений, js, html и других файлов. Но нам также нужна следующая конфигурация
2.1 Разбор файла .vue
npm i -D vue-loader vue-template-compiler vue-style-loader
npm i -S vue
vue-loaderдля разбора.vueдокумент
vue-template-compilerдля составления шаблонов
Конфигурация выглядит следующим образом
const vueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
module:{
rules:[{
test:/\.vue$/,
use:['vue-loader']
},]
},
resolve:{
alias:{
'vue$':'vue/dist/vue.runtime.esm.js',
' @':path.resolve(__dirname,'../src')
},
extensions:['*','.js','.json','.vue']
},
plugins:[
new vueLoaderPlugin()
]
}
2.2 Настройте webpack-dev-server для горячего обновления
npm i -D webpack-dev-server
Конфигурация выглядит следующим образом
const Webpack = require('webpack')
module.exports = {
// ...省略其他配置
devServer:{
port:3000,
hot:true,
contentBase:'../dist'
},
plugins:[
new Webpack.HotModuleReplacementPlugin()
]
}
Полная конфигурация выглядит следующим образом
// webpack.config.js
const path = require('path');
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const Webpack = require('webpack')
module.exports = {
mode:'development', // 开发模式
entry: {
main:path.resolve(__dirname,'../src/main.js'),
},
output: {
filename: '[name].[hash:8].js', // 打包后的文件名称
path: path.resolve(__dirname,'../dist') // 打包后的目录
},
module:{
rules:[
{
test:/\.vue$/,
use:['vue-loader']
},
{
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets:[
['@babel/preset-env']
]
}
}
},
{
test:/\.css$/,
use: ['vue-style-loader','css-loader',{
loader:'postcss-loader',
options:{
plugins:[require('autoprefixer')]
}
}]
},
{
test:/\.less$/,
use: ['vue-style-loader','css-loader',{
loader:'postcss-loader',
options:{
plugins:[require('autoprefixer')]
}
},'less-loader']
}
]
},
resolve:{
alias:{
'vue$':'vue/dist/vue.runtime.esm.js',
' @':path.resolve(__dirname,'../src')
},
extensions:['*','.js','.json','.vue']
},
devServer:{
port:3000,
hot:true,
contentBase:'../dist'
},
plugins:[
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'../public/index.html'),
filename:'index.html'
}),
new vueLoaderPlugin(),
new Webpack.HotModuleReplacementPlugin()
]
}
2.3 Настройка команды упаковки
Сначала создайте новый main.js в src
npm run devВ это время, если браузер показывает, что среда разработки Vue работает успешно, поздравляем, вы успешно сделали первый шаг.
2.4 Различие между средой разработки и производственной средой
При практическом применении к проекту нам необходимо отличать среду разработки от производственной среды.Добавляем еще два файла на основе оригинального webpack.config.js
-
webpack.dev.jsФайл конфигурации среды разработки
开发环境主要实现的是热更新,不要压缩代码,完整的sourceMap
-
webpack.prod.jsФайл конфигурации рабочей среды
生产环境主要实现的是压缩代码、提取css文件、合理的sourceMap、分割代码
需要安装以下模块:
npm i -D webpack-merge copy-webpack-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin
-
webpack-mergeОбъединить конфигурацию -
copy-webpack-pluginкопировать статические ресурсы -
optimize-css-assets-webpack-pluginсжать css -
uglifyjs-webpack-pluginСжатие JS
webpack modeнастраиватьproductionjs код автоматически сжимается. вводить в принципе не надоuglifyjs-webpack-pluginПовторяющаяся работа. ноoptimize-css-assets-webpack-pluginСжатие css уничтожит оригинальное сжатие js, поэтому здесь мы вводимuglifyjsсжимать
2.4.1 webpack.config.js
const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const devMode = process.argv.indexOf('--mode=production') === -1;
module.exports = {
entry:{
main:path.resolve(__dirname,'../src/main.js')
},
output:{
path:path.resolve(__dirname,'../dist'),
filename:'js/[name].[hash:8].js',
chunkFilename:'js/[name].[hash:8].js'
},
module:{
rules:[
{
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env']
}
},
exclude:/node_modules/
},
{
test:/\.vue$/,
use:[{
loader:'vue-loader',
options:{
compilerOptions:{
preserveWhitespace:false
}
}
}]
},
{
test:/\.css$/,
use:[{
loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
options:{
publicPath:"../dist/css/",
hmr:devMode
}
},'css-loader',{
loader:'postcss-loader',
options:{
plugins:[require('autoprefixer')]
}
}]
},
{
test:/\.less$/,
use:[{
loader:devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
options:{
publicPath:"../dist/css/",
hmr:devMode
}
},'css-loader','less-loader',{
loader:'postcss-loader',
options:{
plugins:[require('autoprefixer')]
}
}]
},
{
test:/\.(jep?g|png|gif)$/,
use:{
loader:'url-loader',
options:{
limit:10240,
fallback:{
loader:'file-loader',
options:{
name:'img/[name].[hash:8].[ext]'
}
}
}
}
},
{
test:/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use:{
loader:'url-loader',
options:{
limit:10240,
fallback:{
loader:'file-loader',
options:{
name:'media/[name].[hash:8].[ext]'
}
}
}
}
},
{
test:/\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
use:{
loader:'url-loader',
options:{
limit:10240,
fallback:{
loader:'file-loader',
options:{
name:'media/[name].[hash:8].[ext]'
}
}
}
}
}
]
},
resolve:{
alias:{
'vue$':'vue/dist/vue.runtime.esm.js',
' @':path.resolve(__dirname,'../src')
},
extensions:['*','.js','.json','.vue']
},
plugins:[
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'../public/index.html')
}),
new vueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css'
})
]
}
2.4.2 webpack.dev.js
const Webpack = require('webpack')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge')
module.exports = WebpackMerge(webpackConfig,{
mode:'development',
devtool:'cheap-module-eval-source-map',
devServer:{
port:3000,
hot:true,
contentBase:'../dist'
},
plugins:[
new Webpack.HotModuleReplacementPlugin()
]
})
2.4.3 webpack.prod.js
const path = require('path')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = WebpackMerge(webpackConfig,{
mode:'production',
devtool:'cheap-module-source-map',
plugins:[
new CopyWebpackPlugin([{
from:path.resolve(__dirname,'../public'),
to:path.resolve(__dirname,'../dist')
}]),
],
optimization:{
minimizer:[
new UglifyJsPlugin({//压缩js
cache:true,
parallel:true,
sourceMap:true
}),
new OptimizeCssAssetsPlugin({})
],
splitChunks:{
chunks:'all',
cacheGroups:{
libs: {
name: "chunk-libs",
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: "initial" // 只打包初始时依赖的第三方
}
}
}
}
})
2.5 Оптимизировать конфигурацию WebPack
Вы можете немного устать, видя это, но для того, чтобы получить лучшее предложение и более высокую зарплату, вы должны продолжать копать глубже.
2.5.1 Оптимизация скорости упаковки
Скорость сборки означает, насколько быстро мы можем выполнять горячее обновление каждый раз, когда вносим изменения в код, и насколько быстро мы можем упаковывать файлы перед публикацией.
2.5.1.1 Параметры режима рационального конфигурации и параметры Devtool
modeМожет быть установленdevelopment productionдва параметра
Если не установлено,webpack4будуmodeПо умолчанию установлено значениеproduction
productionрежим будетtree shaking(удаление бесполезного кода) иuglifyjs(обфускация сжатия кода)
2.5.1.2 Сужение области поиска файлов (настройка включения псевдонима и исключения расширений noParse)
-
alias: когда появится наш кодimport 'vue', webpack будет использовать восходящий рекурсивный поиск для поискаnode_modulesНайдите его в каталоге. Чтобы уменьшить область поиска, мы можем напрямую указать webpack, какой путь искать. он же псевдоним(alias) Конфигурация. -
include excludeтакая же конфигурацияinclude excludeтакже может уменьшитьwebpack loaderвремя конверсии поиска. -
noParseкогда наш код используетimport jq from 'jquery'час,webpackОн проанализирует, зависит ли библиотека jq от других пакетов. Но у нас есть похожиеjqueryТакие зависимые библиотеки обычно считаются не ссылающимися на другие пакеты (кроме специальных, судите сами). УвеличиватьnoParseатрибут, расскажитеwebpackНет необходимости парсить, тем самым увеличивая скорость упаковки. -
extensionswebpackбудет основываться наextensionsНайти файлы с заданным суффиксом (сначала записываются типы файлов с более высокой частотой)
2.5.1.3 Используйте HappyPack, чтобы включить преобразование многопроцессорного загрузчика
В процессе создания веб-пакета большая часть времени фактически тратится на синтаксический анализ загрузчика, преобразование и сжатие кода. В ежедневной разработке нам нужно использовать Loader для преобразования js, css, изображений, шрифтов и других файлов, и объем преобразованных файловых данных также очень велик. Из-за однопоточной природы js эти операции преобразования не могут обрабатывать файлы одновременно, а должны обрабатывать файлы один за другим. Основной принцип HappyPack заключается в декомпозиции этой части задачи на несколько подпроцессов для параллельной обработки, после обработки подпроцессов результаты отправляются в основной процесс, тем самым сокращая общее время построения.
npm i -D happypack
2.5.1.4 Использование плагина webpack-parallel-uglify для улучшения сжатия кода
Преобразование погрузчика была оптимизирована выше, поэтому существует еще одна сложность оптимизации времени сжатия кода.
npm i -D webpack-parallel-uglify-plugin
2.5.1.5 Извлечение сторонних модулей
Для статических файлов зависимостей, которые редко изменяются в проектах разработки. похожий на наш
elementUi、vueСемейное ведро и так далее. Поскольку изменения происходят редко, мы не хотим, чтобы эти зависимости были интегрированы в каждую логику сборки. Преимущество этого в том, что каждый раз, когда я изменяю файл своего локального кода,webpackМне нужно только запаковать код файла самого моего проекта без компиляции сторонних библиотек. В будущем, пока мы не будем обновлять сторонние пакеты, тоwebpackЭти библиотеки не будут упакованы, что может быстро повысить скорость упаковки.
Здесь мы используемwebpackВстроенныйDllPlugin DllReferencePluginБыть вытащенным
в сwebpackСоздайте новый файл конфигурации в том же каталогеwebpack.dll.config.jsкод показывает, как показано ниже
// webpack.dll.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = {
// 你想要打包的模块的数组
entry: {
vendor: ['vue','element-ui']
},
output: {
path: path.resolve(__dirname, 'static/js'), // 打包后文件输出的位置
filename: '[name].dll.js',
library: '[name]_library'
// 这里需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
},
plugins: [
new webpack.DllPlugin({
path: path.resolve(__dirname, '[name]-manifest.json'),
name: '[name]_library',
context: __dirname
})
]
};
существуетpackage.jsonНастройте следующую команду в
"dll": "webpack --config build/webpack.dll.config.js"
Далее в нашемwebpack.config.jsДобавьте следующий код
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./vendor-manifest.json')
}),
new CopyWebpackPlugin([ // 拷贝生成的文件到dist目录 这样每次不必手动去cv
{from: 'static', to:'static'}
]),
]
};
воплощать в жизнь
npm run dll
Вы обнаружите, что третье место для нужной нам коллекции сгенерировано
кодvendor.dll.jsмы должныhtmlВручную импортируйте это в файлjsдокумент
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>老yuan</title>
<script src="static/js/vendor.dll.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
Таким образом, если мы не будем обновлять сторонние зависимости, нам не нужноnpm run dll. прямое исполнениеnpm run dev npm run buildВы обнаружите, что наша скорость упаковки значительно улучшилась. потому что мы прошлиdllPluginИзвлеченные сторонние зависимости.
2.5.1.6 Настройка кэша
Каждый раз, когда мы выполняем сборку, мы будем повторно компилировать все файлы. Можно ли кэшировать такую повторяющуюся работу? Ответ - да. В настоящее время большинство файлов
loaderпри условииcacheэлемент конфигурации. например, вbabel-loader, вы можете установитьcacheDirectoryвключить кэширование,babel-loader?cacheDirectory=trueОн будет записывать каждый результат компиляции в файл на жестком диске (по умолчанию в корневом каталоге проекта).node_modules/.cache/babel-loaderВ каталоге конечно тоже можно настроить)
но еслиloaderОн не поддерживает кеширование? У нас также есть методы, мы можем передатьcache-loader, то, что он делает, простоbabel-loaderвключиcache после того, как вы сделаете то, чтоloaderРезультаты компиляции записываются в кэш жесткого диска. Повторное построение сначала сравнит его, и если файл не изменился по сравнению с предыдущим, кеш будет использоваться напрямую. Метод использования показан в официальной демонстрации, просто добавьте этот загрузчик перед другим загрузчиком с высокой производительностью.
npm i -D cache-loader
2.5.2 Оптимизация размера файла пакета
Мы оптимизировали скорость упаковки, но объем упакованного файла очень большой, из-за чего страница загружается медленно и расходуется трафик, поэтому продолжим оптимизировать размер файла.
2.5.2.1 Добавление webpack-bundle-analyzer для анализа упакованных файлов
webpack-bundle-analyzerОтобразите упакованный пакет контента в виде интуитивно понятной древовидной диаграммы для удобства взаимодействия, сообщите нам, что на самом деле представлено в пакете, который мы создаем.
npm i -D webpack-bundle-analyzer
package.jsonнастроить команду запуска
"analyz": "NODE_ENV=production npm_config_report=true npm run build"
окна, пожалуйста, установитеnpm i -D cross-env
"analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"
следующийnpm run analyzБраузер автоматически откроет веб-страницу графа зависимостей файлов.
2.5.2.3 externals
Согласно официальной документации, если мы хотим сослаться на библиотеку, но не хотим
webpackупакованы и не влияют на наше использование в программеCMD、AMDилиwindow/globalЕсли он используется глобально, его можно использовать, настроивExternals. Эта функция в основном используется при создании библиотеки, но ее можно полноценно использовать и в разработке нашего проекта.ExternalsТаким образом, мы удаляем из логики сборки эти статические ресурсы, которые не нужно упаковывать, и используемCDNспособ цитировать их.
Иногда мы хотим, чтобы мы прошлиscriptПредставленные библиотеки, например импортированные CDN.jquery, когда мы используем его, мы по-прежнему используемrequireспособ использовать, но не хочуwebpackСнова скомпилируйте его в файл. Случай с официальным сайтом здесь достаточно ясен, если вам интересно, вы можете нажать, чтобы понять
webpackОфициальный сайт дела выглядит следующим образом
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous">
</script>
module.exports = {
//...
externals: {
jquery: 'jQuery'
}
};
import $ from 'jquery';
$('.my-element').animate(/* ... */);
2.5.2.3 Tree-shaking
Вот отдельное упоминание
tree-shaking, потому что здесь есть яма.tree-shakingОсновная роль заключается в очистке бесполезных частей кода. Сейчас я вwebpack4мы устанавливаемmodeдляproductionОн автоматически включается, когдаtree-shaking. Но чтобы это работало, сгенерированный код должен быть модулем ES6. Вы не можете использовать другие типы модулей, такие какCommonJSрод. При использованииBabelто здесь есть небольшая проблема, потому чтоBabelПредустановка по умолчанию преобразует любой тип модуля вCommonJSтипа, в результате чегоtree-shakingневерный. Исправить эту проблему также просто, в.babelrcфайл или вwebpack.config.jsустановить в файлmodules: falseДостаточно
// .babelrc
{
"presets": [
["@babel/preset-env",
{
"modules": false
}
]
]
}
или
// webpack.config.js
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', { modules: false }]
}
},
exclude: /(node_modules)/
}
]
}
После крещения двух вышеупомянутых серий мы стали квалифицированным инженером по настройке веб-пакетов. Однако заменяемость самого себя все равно очень высока просто завинчиванием шурупов.Далее углубимся в принцип работы вебпака.
3 серии рукописных веб-пакетов
Опытные два раздела выше, мы можем уже квалифицированным и плагин-загрузчиком, связанным с использованием нашего конвертации кода, разрешения. Далее мы вручную реализуем свой собственный погрузчик и плагин, делая его веселее в обычном развитии.
3.1 Рукописный ввод Webpack Loader
loaderПо сути, этоnodeмодуль. аналог соковыжималки(loader)Преобразование соответствующего типа кода файла(code)дай это. По установленным нами правилам, он возвращает нам переработанный сок после его серии переработок.(code).
loaderпринципы письма
- Единый принцип: каждый
Loaderделать только одно; - Связанные вызовы:
Webpackбудет связывать каждый вызов по порядкуLoader; - Объединяющий принцип: Следуйте
WebpackУстановленные правила проектирования и структура, вход и выход - строки, каждыйLoaderПолностью независимый, подключи и играй;
В повседневной среде разработки, чтобы облегчить отладку, мы часто добавляем многоconsoleРаспечатать. Но мы не хотим, чтобы печатное значение существовало в производственной среде. Итак, здесь мы реализуемloaderудалить кодconsole
распространение знаний
AST.ASTС точки зрения непрофессионала, предположим, что у нас есть файлa.js,Мыa.js1000 строк внутри выполняют некоторые операции, например, для всехawaitУвеличиватьtry catchи другие операции, ноa.jsКод внутри, по сути, представляет собой набор строк. Итак, что мы делаем, то есть преобразуем его в объект с размеченной информацией (абстрактное синтаксическое дерево), и мы можем легко добавлять, удалять, изменять и проверять. Этот помеченный объект (абстрактное синтаксическое дерево)AST. Здесь рекомендуется хорошая статья ASTБыстрый старт АСТ
npm i -D @babel/parser @babel/traverse @babel/generator @babel/types
-
@babel/parserРазобрать исходный код наAST -
@babel/traverseправильноASTУзлы рекурсивно просматриваются для создания удобной операции и преобразования.pathобъект -
@babel/generatorБудуASTГенерация декодированияjsкод -
@babel/typesБлагодаря этому модулю конкретныеASTУзлы добавляются, удаляются, модифицируются и ищутся
новыйdrop-console.js
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const generator = require('@babel/generator').default
const t = require('@babel/types')
module.exports=function(source){
const ast = parser.parse(source,{ sourceType: 'module'})
traverse(ast,{
CallExpression(path){
if(t.isMemberExpression(path.node.callee) && t.isIdentifier(path.node.callee.object, {name: "console"})){
path.remove()
}
}
})
const output = generator(ast, {}, source);
return output.code
}
как использовать
const path = require('path')
module.exports = {
mode:'development',
entry:path.resolve(__dirname,'index.js'),
output:{
filename:'[name].[contenthash].js',
path:path.resolve(__dirname,'dist')
},
module:{
rules:[{
test:/\.js$/,
use:path.resolve(__dirname,'drop-console.js')
}
]
}
}
Фактически,
webpack4consoleфункция, вminimizerнастраивается вудалить консоль
Прикрепить официальный сайтКак написать загрузчик
3.2 Рукописный плагин веб-пакета
существует
WebpackМногие события транслируются в течение жизненного цикла бега,PluginВы можете слушать эти события и проходить их в нужное времяWebpackкоторый предоставилAPIИзменить результат вывода. С точки зрения непрофессионала: вкусная тарелкаЯичница-болтунья с солью и фасольюОн должен пройти через процесс обжига масла, жарки, приправы до конечной тарелки и т. д.pluginЭто эквивалентно мониторингу каждой ссылки и работе с ней.Например, вы можете написать сценарий с меньшим количеством перца.plugin, мониторwebpackОткрытое событие жизненного цикла (приправа) выполняет операцию без перца при приправе. тогда это то же самое, чтоloaderВ чем разница? Мы также упоминали вышеloaderединый принципloaderтолько одно вродеless-loader, можно только разобратьlessдокумент,pluginОн заключается в выполнении широкого круга задач за весь процесс.
Базовая структура плагина выглядит следующим образом.
class firstPlugin {
constructor (options) {
console.log('firstPlugin options', options)
}
apply (compiler) {
compiler.plugin('done', compilation => {
console.log('firstPlugin')
))
}
}
module.exports = firstPlugin
Что такое компилятор и компиляция?
-
compilerобъект содержитWebpackВся информация о конфигурации для среды. Этот объект запускаетсяwebpackсоздается один раз и настраивается со всеми рабочими параметрами, включаяoptions,loaderа такжеplugin. КогдаwebpackКогда подключаемый модуль применяется в среде, подключаемый модуль получает этоcompilerссылка на объект. можно использовать для доступаwebpackосновное окружение. -
compilationОбъект содержит текущие ресурсы модуля, скомпилированные ресурсы, измененные файлы и т. д. при бегеwebpackПри разработке ПО промежуточного слоя всякий раз, когда обнаруживается изменение файла, создается новыйcompilationДля создания нового набора скомпилированных ресурсов.compilationОбъект также предоставляет ряд ключевых коррекций синхронизации, выберите, чтобы использовать при выполнении пользовательских плагинов для обработки.
Разница между компилятором и компиляцией в том, что
-
Компилятор представляет собой весь жизненный цикл веб-пакета от запуска до завершения работы, а компиляция просто представляет собой новый процесс компиляции.
-
Компилятор и компилятор выявляют множество хуков, и мы можем настроить обработку в соответствии с реальными потребностями сцены.
документация по хукам компилятора
документация по хуку компиляции
Теперь нам нужно вручную разработать простую, автоматически сгенерированную информацию о размере пакета документов перед созданием файла пакета.
создать новыйwebpack-firstPlugin.js
class firstPlugin{
constructor(options){
this.options = options
}
apply(compiler){
compiler.plugin('emit',(compilation,callback)=>{
let str = ''
for (let filename in compilation.assets){
str += `文件:${filename} 大小${compilation.assets[filename]['size']()}\n`
}
// 通过compilation.assets可以获取打包后静态资源信息,同样也可以写入资源
compilation.assets['fileSize.md'] = {
source:function(){
return str
},
size:function(){
return str.length
}
}
callback()
})
}
}
module.exports = firstPlugin
как использовать
const path = require('path')
const firstPlugin = require('webpack-firstPlugin.js')
module.exports = {
// 省略其他代码
plugins:[
new firstPlugin()
]
}
воплощать в жизньnpm run buildможно увидеть вdistФайл, содержащий информацию о файле пакета, создается в папкеfileSize.md
два выше
loaderа такжеpluginСлучай только руководство, фактические потребности развитияloaderа такжеpluginЕсть много аспектов, которые следует учитывать, и рекомендуется попробовать это самостоятельно.
Прикрепить официальный сайтКак написать плагин
3.3 Рукописный веб-пакет
Потому что пространство слишком длинное, а принцип более глубокий. Ввиду принципа этой статьи быстро приступить к работе и применительно к реальной разработке, я решил начать новую статью для ее подробного анализа.
webpackпринцип и реализацияdemoВерсия. После калибровки формата ссылка на статью будет размещена ниже
4 Эпоха веб-пакета 5.0
Скорость обновления как интерфейсных фреймворков, так и инструментов сборки выходит далеко за рамки нашего воображения.jqueryПрошли времена шаттла. То, что мы хотим принять, — это постоянное обновление и итерация.vue、react、node、serverless、docker、k8s....
webpack5.0Предназначен для упрощения настройки и облегчения начала работы (webpack4я также сказал это предложение), и некоторые улучшения производительности
- Используйте постоянный кеш для повышения производительности сборки;
- Улучшите долгосрочное кэширование с помощью лучших алгоритмов и значений по умолчанию;
- Очистить внутреннюю структуру без внесения каких-либо критических изменений;
- Внесите некоторые критические изменения, чтобы оставаться с версией 5 как можно дольше.
В настоящее время сопровождающие обновляются очень часто, я думаю, это не займет много времени.webpack5.0охватит массы. Заинтересованные студенты могут установить его первымbetaверсию попробовать. Но перед этим рекомендуетсяwebpack4Сделайте мастеринг, чтобы дорога позади становилась все лучше и лучше.