предисловие
Приближается 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')
})
]
}
Сгенерированный каталог выглядит следующим образом (рисунок)
Может быть обнаружено, что файл JS, сгенерированный упаковкой, был автоматически введен в файл HTML1.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.
В то же время нам также нужны некоторые загрузчики для разбора наших файлов css.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-loader
8.x соответствующийbabel-core
7.x -
babel-loader
7.х перепискаbabel-core
6.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Создайте новый App.vueСоздайте новую общую папку и создайте внутри новый index.html.воплощать в жизнь
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
настраиватьproduction
js код автоматически сжимается. вводить в принципе не надо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
Нет необходимости парсить, тем самым увеличивая скорость упаковки. -
extensions
webpack
будет основываться на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.js
1000 строк внутри выполняют некоторые операции, например, для всех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')
}
]
}
}
Фактически,
webpack4
console
функция, в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
Сделайте мастеринг, чтобы дорога позади становилась все лучше и лучше.