Количество слов: 3700
Время чтения: 15 минут
Среда: webpack3.8.1
предисловие
Некоторое время назад, когда я использовал webpack для проверки информации, я обнаружил, что это либо статья начального уровня, либо статья о том, как оптимизировать скорость упаковки или как использовать плагин или загрузчик. Полного решения по использованию вебпака в реальном проекте для справки найти не удалось, поэтому я потратил много сил на интеграцию материалов, просмотр кода и наступание на ямы.
Поэтому я поделюсь схемой конфигурации, которую я изучил, в надежде предоставить какую-то ссылку. Неадекватно, приветствую всех исправить.
Чтобы объяснить, эта статья предназначена для описания идей и проблем, с которыми вы сталкиваетесь, и не будет включать основные объяснения. Если вы хотите понять основы, вот два очень хороших вводных материала, которые вы можете порекомендовать:
Для начала работы с Webpack этого достаточно: Предварительное понимание использования веб-пакета было просто отработано.
китайская документация webpack: эта версия официальной документации была значительно улучшена по сравнению с давно критикуемой проблемой путаницы в документах, и это лучший учебный материал.
текст
Чтобы повысить удобочитаемость и удобство сопровождения кода, я разделил конфигурацию на следующие пять файлов конфигурации:
webpack.common.config.js | общедоступная конфигурация |
---|---|
webpack.dev.config.js | Конфигурация среды разработки |
webpack.prod.config.js | Конфигурация производственной среды |
webpack.dll.config.js | Общая конфигурация библиотеки |
webpack.alias.js | Конфигурация адреса модуля |
Чтобы повысить эффективность упаковки, я упакую некоторый код и сторонние библиотеки с небольшими изменениями в публичные библиотеки.webpack.dll.config.js
Он предназначен для упаковки конфигурационного файла публичной библиотеки, если содержимое в нем не изменится, то последующая упаковка не будет обрабатывать эти файлы, что значительно повышает эффективность упаковки. Если вы используете больше сторонних библиотек, настоятельно рекомендуется использовать этот метод для упаковки.
Поскольку существует много различий между конфигурацией среды разработки и конфигурацией производственной среды, конфигурация выполняется отдельно, в соответствии сwebpack.dev.config.js
а такжеwebpack.prod.config.js
конфигурационный файл. Затем извлеките его общедоступную часть, это наш общедоступный файл конфигурации.webpack.common.config.js
.
Наконец, автор сделал конфигурацию псевдонимов для каждого модуля, чтобы отделить зависимость кода от каталога кода, соответствующего нашемуwebpack.alias.js
конфигурационный файл.
Далее давайте обсудим конкретное содержимое этих пяти файлов конфигурации.
1.webpack.common.config.js
Публичная конфигурация, сначала код:
const wepackMerge = require('webpack-merge');
const Path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const Webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
const GTLoaderFilesPlugin = require('./plugins/gt-file-loader-plugin');
const ProdConfig = require('./webpack.prod.config');
const DevConfig = require('./webpack.dev.config');
const alias = require('./webpack.alias');
const dlls = require('./webpack.dll.config');
//根据条件处理相关配置
const genarateConfig = env => {
//样式loader
let cssLoader = [{
loader: 'css-loader',
options: {
sourceMap: true
}
}, {
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
require('postcss-cssnext')()
],
sourceMap: true
}
}, {
loader: 'less-loader',
options: {
sourceMap: true
}
}];
let styleLoader = [{
test: /\.(css|less)$/,
use: env === 'prod' ? ExtractTextPlugin.extract({
fallback: 'style-loader',
use: cssLoader
}) : [{
loader: 'style-loader',
options: {
sourceMap: true
}
}].concat(cssLoader)
}];
//脚本loader
let jsLoader = [{
test: /\.js$/,
exclude: /(node_modules|bower_components|libs)/,
use: [{
loader: 'babel-loader'
}].concat(env === 'dev' ? [{
loader: 'eslint-loader'
}] : [])
}];
//文件处理loader
let fileLoaderOptions = {
useRelativePath: false,
name: '[name]-[hash:5].[ext]'
};
if (env === 'prod') {
fileLoaderOptions.limit = 10000;
}
let fileLoader = [{
test: /\.(jpg|jpeg|png|icon)$/,
use: [{
loader: env === 'dev' ? 'file-loader' : 'url-loader',
options: env === 'dev' ? fileLoaderOptions : Object.assign({}, fileLoaderOptions, {
outputPath: '../dist/img'
})
}]
}, {
//解析字体文件
test: /\.(eot|svg|ttf|woff2?)$/,
use: [{
loader: env === 'dev' ? 'file-loader' : 'url-loader',
options: env === 'dev' ? fileLoaderOptions : Object.assign({}, fileLoaderOptions, {
outputPath: '../dist/fonts'
})
}]
}, {
//解析主页面和页面上的图片
test: /\.html$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'html-loader',
options: {
attrs: ['img:src', 'img:data-src'],
minimize: true
}
}
}];
//webpack插件
let plugins = [];
//组织第三方库插件
for (let key in dlls.entry) {
//组织DllReferencePlugin
let dllPlugin = new Webpack.DllReferencePlugin({
manifest: require('../dll/manifest/' + key + '.manifest.json')
});
plugins.push(dllPlugin);
}
//加载js
plugins.push(new AddAssetHtmlPlugin({
filepath: Path.join(__dirname, '../dll/*.js'),
hash: true,
includeSourcemap: false,
publicPath: './dll/',
outputPath: '../dist/dll/'
}));
//加载css
plugins.push(new AddAssetHtmlPlugin({
filepath: Path.join(__dirname, '../dll/*.css'),
hash: true,
typeOfAsset: 'css',
includeSourcemap: false,
publicPath: './dll/',
outputPath: '../dist/dll/'
}));
//入口html插件
plugins.push(new HtmlWebpackPlugin({
template: Path.join(__dirname, '../src/control.html'),
filename: 'index.html',
inject: true,
chunks: ['vendor', 'example']
}));
//拷贝文件
plugins.push(new CopyWebpackPlugin([{
// 第三方的字体文件
from: './dll/fonts',
to: '../dist/fonts'
}, {
//表单页面文件
from: './src/form/core/views',
to: '../dist/core-views'
}, {
//表单页面文件
from: './src/form/office/views',
to: '../dist/office-views'
}], {
ignore: ['**/.svn/**']
}));
//友好提示插件
plugins.push(new FriendlyErrorsPlugin());
//不打包默认加载项
plugins.push(new Webpack.IgnorePlugin(/^\.\/locale$/, /moment$/));
//将加载项写入loader.js中
plugins.push(new GTLoaderFilesPlugin());
let config = {
devtool: 'source-map',
output: {
path: Path.join(__dirname, '../dist/'),
filename: env === 'dev' ? '[name]-[hash:5].bundle.js' : '[name]-[chunkhash:5].bundle.js'
},
module: {
rules: [].concat(styleLoader).concat(jsLoader).concat(fileLoader)
},
plugins: plugins,
resolve: {
alias: alias
}
};
return config;
};
module.exports = env => {
let config = env === 'dev' ? DevConfig : ProdConfig;
let result = wepackMerge(genarateConfig(env), config);
return result;
};
Вход
Как среда разработки, так и производственная среда используют этот файл конфигурации для выполнения веб-пакета, который отличается переменными среды, передаваемыми при выполнении команды CLI. Входящая среда разработкиdev
, производственная среда передается вprod
, с помощью команды npm scripts это можно реализовать удобнее, код такой:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --env prod --config build/webpack.common.config.js",
"server": "webpack-dev-server --env dev --config build/webpack.common.config.js --open",
"dll": "webpack --config build/webpack.dll.config.js"
}
бегатьnpm run server
Вы можете открыть среду разработки.
В общедоступной конфигурации сгенерированный код конфигурации выглядит следующим образом:
module.exports = env => {
let config = env === 'dev' ? DevConfig : ProdConfig;
let result = wepackMerge(genarateConfig(env), config);
return result;
};
использоватьwebpack-mergeПлагин, который объединяет различные конфигурации с общей конфигурацией в соответствии с переданными параметрами. Обратите внимание, что поскольку загрузчик выполняется в обратном порядке, конфигурация, связанная с загрузчиком, не может быть интегрирована таким образом и может обрабатываться только в коде сама по себе. здесьgenarateConfig
Это функция, которая обрабатывает общедоступную конфигурацию.
стиль
Рабочая среда: less-loader→postcss-loader→css-loader→extract-text-webpack-plugin
Среда разработки: less-loader→postcss-loader→css-loader→style-loader
less-loader: webpack поставляется с загрузчиком, предварительно компилирует меньше файлов и компилирует меньше синтаксиса в синтаксис css.
postcss-loader: webpack поставляется с загрузчиком, инструментом преобразования css, который автоматически добавляет префиксы браузера, сжимает css и поддерживает будущий синтаксис.
css-loader: webpack поставляется с загрузчиком для компиляции css.
extract-text-webpack-plugin: webpack поставляется с плагинами,extract()
Функция вернет загрузчик, который выводит независимые файлы стилей, которые обычно используются в производственных средах.
style-loader: webpack поставляется с загрузчиком, который напрямую вставляет стили в html-документ в виде тегов стилей.
Уведомление:Модуль postcss-cssnext представлен в postcss-loader, который может поддерживать будущий синтаксис. все настройки загрузчикаsourceMap: true
Чтобы увидеть исходный код стиля в консоли.
сценарий
Производственная среда: babel-loader
Среда разработки: eslint-loader→babel-loader
eslint-loader:webpack自带loader,需要依赖Eslint工具,做静态代码检查只用。 Ты можешь встретитьwebpack-dev-serverИспользуется накладка.
babel-loader: Компиляция js, совместимая с новыми функциями.
документ
Рабочая среда: html-загрузчик → URL-загрузчик
Среда разработки: html-loader→file-loader
html-loader: webpack поставляется с загрузчиком, компилирует html-файл и обрабатывает загруженные изображения и другие ресурсы как модули.
url-loader: webpack поставляется с загрузчиком, который анализирует файловые ресурсы, такие как изображения и шрифты, и может анализировать ресурсы, превышающие лимит, в строки в кодировке base64 для достижения эффекта оптимизации за счет уменьшения количества запросов.
file-loader: webpack поставляется с загрузчиком, таким же, как url-loader, но не анализирует файл в строку в кодировке base64.
плагин
DllReferencePlugin: webpack поставляется с плагинами для работы с общедоступными библиотеками.webpack.dll.config.js
использовать.
add-asset-html-webpack-plugin: автоматически вставлять ресурсы в сгенерированную html-страницу, которая используется здесь для представления ресурсов js и css в общедоступной библиотеке.
html-webpack-plugin: создание файлов html на основе шаблонов и поддержка синтаксиса шаблонов ejs по умолчанию. Примечание. При совместном использовании с html-loader, поскольку html-loader сначала скомпилирует html-файл в строку, синтаксический анализ ejs завершится ошибкой. Решение, которое я использую, заключается в следующем: все суффиксы, использующие синтаксис ejs, меняются на .ejs, а файлы ресурсов, такие как загруженные в них изображения, загружаются вручную модулями. пример:<img src="${require('./assets/img/6.jpg')}" alt="">
. Тогда html-загрузчик не разбирает файлы с суффиксом ejs.
copy-webpack-plugin: webpack поставляется с плагином для копирования файлов.В основном он копирует файлы ресурсов, которые не представлены как модули, такие как некоторые графические шрифты и другие файлы.Компилировать их не нужно.Быстрее скопировать их напрямую.
friendly-errors-webpack-plugin: Дружественный плагин подсказок, визуализация подсказок в CLI более удобна. Нет необходимости устанавливать этот плагин, если вы используете git bash или терминал Mac.
IgnorePlugin: webpack поставляется с плагином и не упаковывает надстройку по умолчанию. Webpack по умолчанию упаковывает локаль, момент и другие модули. Если проекту это не нужно, вы можете использовать этот плагин для щита.
GTLoaderFilesPlugin: это мой собственный плагин для загрузки ресурсов, который можно игнорировать.
основная конфигурация
контекст: ссылочный путь для настройки записи и загрузчика.
resolve.alias: конфигурация псевдонима модуля, используемая с webpack.alias.js
2.webpack.dev.config.js
Конфигурация среды разработки, первый код:
const Webpack = require('webpack');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
entry: {
example: './examples/index.js'
},
devServer: {
port: '9091',
overlay: true,
//设置为false则会在页面中显示当前webpack的状态
inline: true,
historyApiFallback: true,
//代理配置
proxy: {
},
hot: true
//强制页面不通过刷新页面更新文件
// hotOnly: true
},
plugins: [
//分析插件
// new BundleAnalyzerPlugin(),
//模块热更新插件
new Webpack.HotModuleReplacementPlugin(),
//使用HMR时显示模块的相对路径
new Webpack.NamedModulesPlugin()
]
};
devServer: настроить сервер, поставляемый с веб-пакетом, только для отладки. необходимо установитьwebpack-dev-serverПлагины, обратите внимание, что могут быть установлены только версии до V3.Версия V3 совместима с webpack4 и не может использоваться в webpack3.
webpack-bundle-analyzer: сторонний подключаемый модуль для анализа, который может анализировать упакованные результаты. Вы также можете использовать официальное решение для анализа: В сочетании с плагинамиstats-webpack-pluginСгенерированные файлы результатов анализа и официальные онлайн-инструментыофициальный инструментПроанализировать результаты упаковки.
HotModuleReplacementPlugin: WebPack поставляется с инструментами, модуль горячего обновления должен быть плагином.
NamedModulesPlugin: webpack поставляется с плагином, а модуль называется путем к модулю, и результат работы более понятен. Без этого плагина веб-пакет по умолчанию будет использовать случайное имя идентификатора. Для отладки официальная рекомендуемая среда разработки должна использовать плагины.
3.webpack.prod.config.js
Конфигурация рабочей среды, первый код:
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const Webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const ZipPlugin = require('zip-webpack-plugin');
const StatsPlugin = require('stats-webpack-plugin');
const SvnInfo = require('svn-info').sync('https://218.106.122.66/svn/framework/trunk/gt-ui', 'HEAD');
const Path = require('path');
const pkg = require('../package.json');
module.exports = {
entry: {
frame0: 'frame',
frame2: 'frame2',
frame3: 'frame3',
center1: 'center1',
center2: 'center2',
center3: 'center3',
login1: 'login1',
login2: 'login2',
form: 'form',
example: './examples/index.js'
},
plugins: [
//模块分析页面
// new BundleAnalyzerPlugin(),
new Webpack.optimize.CommonsChunkPlugin({
names: ['vendor'],
minChunks: 2
}),
//混淆代码
new UglifyJsPlugin({
sourceMap: true,
//多线程处理
parallel: true,
//使用缓存
cache: true
}),
//提取css文件
new ExtractTextPlugin({
filename: '[name]-[hash:5].css'
}),
new CleanWebpackPlugin(['dist', 'package'], {
root: Path.join(__dirname, '../')
}),
new Webpack.NamedChunksPlugin(),
new Webpack.NamedModulesPlugin(),
//版本信息
new Webpack.BannerPlugin({
banner: `Name: ${pkg.name}\nSVNVersion: ${SvnInfo.revision}\nDate: ${new Date().toISOString().slice(0, 10)}\nDescription: ${pkg.description}`,
raw: false,
entryOnly: true,
include: /\.js/g
}),
//分析结果
new StatsPlugin('../stats.json', {
chunkModules: true,
exclude: [/node_modules/]
}),
//复制文档页面
new CopyWebpackPlugin([{
// 第三方的字体文件
from: './examples',
to: '../dist/examples'
}, {
//表单页面文件
from: './docs',
to: '../dist/docs'
}], {
ignore: ['**/.svn/**']
}),
//打包生成包的主页
new HtmlWebpackPlugin({
template: Path.join(__dirname, '../src/index.html'),
filename: '../index.html',
inject: true
}),
//压缩文件夹
new ZipPlugin({
filename: 'gt-ui.zip',
path: '../package/',
pathPrefix: 'dist'
})
],
profile: true
};
CommonsChunkPlugin: Webpack поставляется с подключаемым модулем, который извлекает общий код из нескольких записей, что является одним из первых основных преимуществ webpack для реализации кода.
uglifyjs-webpack-plugin: Плагин сжатия и обфускации кода, включение многопоточности и кэширования может ускорить упаковку.
clean-webpack-plugin: очистить подключаемый модуль папки и очистить остаточные файлы перед каждым пакетом.
NamedChunksPlugin: WebPack поставляется с плагином, и, как говорят, среда разработки имеет длительный кэш. Если этот плагин не используется, сгенерированный WebPack сгенерированный случайным идентификатором, приведет к изменению значения хеша, соответствующему кодовым файлам кода, что приведет к длительному кэше.
NamedModulesPlugin: То же, что и выше, это работает с модулями, от которых зависит чанк.
BannerPlugin: webpack поставляется с плагином, который добавляет в код сегменты кода, такие как версия кода, авторские права и другая информация.
svn-info: получить информацию SVN о текущем коде.
stats-webpack-plugin: создание упакованного файла анализа для использования в официальном онлайн-инструменте анализа.
zip-webpack-plugin: Сжать результат упаковки в сжатый пакет. При использовании этого плагина я столкнулся с проблемой неправильного порядка выполнения плагина, что привело к сбою упаковки. При той же конфигурации иногда плагин будет выполняться раньше других плагинов, и есть проблема, что файлы, которые нужно сжать, еще не сгенерированы, что приводит к прерыванию упаковки, но иногда этого не происходит. Я проверил некоторую информацию и обнаружил, что, если сам плагин не обрабатывает порядок выполнения, порядок выполнения плагинов веб-пакета на самом деле неопределен (слегка искажен, gulp более точен в сравнении). Вот альтернативный плагин,filemanager-webpack-plugin.
4.webpack.dll.config.js
Общая конфигурация библиотеки, сначала код:
const Path = require('path');
const Webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const alias = require('./webpack.alias');
module.exports = {
entry: {
ngs: ['angular', 'angular-resource', 'angular-sanitize', '@uirouter/angularjs',
'angular-animate', 'angular-touch', 'angular-cookies'
],
ngui: ['jquery', 'sweetalert', 'datetimepickerCN', 'datetimepicker', 'angular-loading-bar', 'angular-strap', 'angular-ui-grid', 'ui-select',
'angular-ui-tour', 'angular-ui-tree', 'angular-validation', 'angular-carousel'
],
base: ['babel-polyfill', 'lodash']
},
output: {
path: Path.join(__dirname, '../dll'),
filename: '[name].dll.js',
library: '[name]'
},
resolve: {
alias: alias
},
plugins: [
new Webpack.DllPlugin({
path: Path.join(__dirname, '../dll/manifest/', '[name].manifest.json'),
name: '[name]'
}),
new CopyWebpackPlugin([{
from: './src/libs/bootstrap-datetimepicker-master/css/bootstrap-datetimepicker.min.css'
}, {
from: './node_modules/angular-loading-bar/build/loading-bar.css'
}, {
from: './node_modules/ui-select/dist/select.css'
}, {
from: './node_modules/angular-ui-tree/dist/angular-ui-tree.min.css'
}, {
from: './node_modules/angular-carousel/dist/angular-carousel.min.css'
}])
]
};
Здесь, для ускорения упаковки, я напрямую копирую некоторые файлы, которые не нужно компилировать плагином копирования, и загружаю их в код.
DllPlugin: webpack поставляется с плагинами для создания файлов определения библиотеки, взаимодействует сDllReferencePluginиспользовать.
5.webpack.alias.js
Конфигурация псевдонима модуля, первый код:
var Path = require('path');
module.exports = {
api: Path.join(__dirname, '../src/common/api'),
//自定义控件
ngControl: Path.join(__dirname, '../src/custom/controls/control'),
//框架
frame: Path.join(__dirname, '../src/custom/frame/frame'),
frame1: Path.join(__dirname, '../src/custom/frame/frame1/frame'),
frame2: Path.join(__dirname, '../src/custom/frame/frame2/frame'),
frame3: Path.join(__dirname, '../src/custom/frame/frame3/frame'),
login1: Path.join(__dirname, '../src/custom/login/login1/login'),
login2: Path.join(__dirname, '../src/custom/login/login2/login'),
center1: Path.join(__dirname, '../src/custom/system-center/center1/system-center'),
center2: Path.join(__dirname, '../src/custom/system-center/center2/system-center'),
center3: Path.join(__dirname, '../src/custom/system-center/center3/system-center'),
frameManager: Path.join(__dirname, '../src/custom/frame-manager')
};
Это необходимо для настройки конкретных адресов файлов, соответствующих различным модулям для обслуживания.
Наша конфигурация сборки делится на две категории: конфигурация фреймворка и конфигурация системы приложений. Выше приведена конфигурация построения фронтенд-фреймворка, я поделюсь с вами конфигурацией построения прикладной системы в следующей статье!