Адрес склада из примера, использованного в этой статье:gayhub
В предыдущем разделе мы решили задачу разработки и отладки проекта, также были настроены среда производства и разработки проекта, а также согласована спецификация конфигурационного файла Webpack. Но это все еще грубо, и в этом разделе мы вместе отполируем эту конфигурацию.
Оптимизация опыта разработки
Замена горячего модуля
В предыдущей конфигурации мы использовалиMiniCssExtractPlugin.loader
заменитьstyle-loader
, потому что нам нужно отделить CSS от JS. Но в MiniCssExtractPlugin все же есть скрытая опасность, то есть он может повлиять на функцию hmr (горячая замена модуля) До того, как он поддерживает hmr, мы можем использовать его только в продакшене.
webpack.base.conf.js
module.exports = {
module: {
rules: [
{
test: /\.styl(us)?$/,
use: [
process.env.NODE_ENV !== 'production' ?
'vue-style-loader' : {
loader: resolve('node_modules/mini-css-extract-plugin/dist/loader.js'),
options: {
publicPath: '../'
}
},
{
loader: 'css-loader',
options: {
importLoaders: 2 // 在 css-loader 前执行的 loader 数量
}
},
'postcss-loader',
{
loader: 'stylus-loader',
options: {
preferPathResolver: 'webpack' // 优先使用 webpack 用于路径解析,找不到再使用 stylus-loader 的路径解析
}
}
]
}
]
}
}
На самом деле, когда я видел элемент конфигурации hmr в последний раз, когда я его использовал, я думал, что он уже поддерживается.Пожалуйста, посмотрите, поддерживается он или нет.MiniCssExtractPlugin Docs
Улучшите скорость сборки: используйте DllPlugin и DllReferencePlugin для предварительной упаковки общедоступных зависимостей.
Когда проект достигнет определенного размера, требования к оптимизации скорости упаковки и производительности горячей загрузки будут повышены, ведь никто не хочет тратить десять секунд или даже минут на ожидание обновления модифицированного вида после модификации. Далее я представлю некоторые общие стратегии оптимизации, но следует отметить, что сам проект не может наступить на некоторые ямы, которые нельзя оптимизировать, есть две известные ямы: супермногостраничность (html-webpack-plugin Обновлять все страницы во время горячей обновление) И динамическая загрузка не указывает явный путь (все страницы в каталоге пакета).
DllPlugin и DllReferencePlugin однозначно лучшие инструменты для оптимизации скорости упаковки.Он может заранее упаковать некоторые публичные зависимости.При последующей упаковке эти зависимости не будут упакованы, а будет использоваться непосредственно упакованный код.Обычно его можно уменьшить на 20 % ~ 40 % времени упаковки, конечно, есть и недостатки:
- Во время инициализации и соответствующих обновлений зависимостей необходимо выполнить дополнительную команду.
- Обычно dll находится в
.html
Внесенные в файл злоупотребления приведут к замедлению загрузки первого экрана
Но в целом плюсы перевешивают минусы.
-
новый
webpack.dll.conf.js
const webpack = require('webpack') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const { resolve } = require('./utils') const libs = { _frame: ['vue', 'vue-router', 'vuex'], _utils: ['lodash'] } module.exports = { mode: 'production', entry: { ...libs }, performance: false, output: { path: resolve('dll'), filename: '[name].dll.js', library: '[name]' // 与 DllPlugin.name 保持一致 }, plugins: [ new CleanWebpackPlugin({ cleanOnceBeforeBuildPatterns: [] }), new webpack.DllPlugin({ name: '[name]', path: resolve('dll', '[name].manifest.json'), context: resolve('') }) ] }
-
существует
webpack.common.conf.js
Использование плагина DllReferencePluginwebpack.common.conf.js
const { generateDllReferences, generateAddAssests } = require('./utils') module.exports = { plugins: [ ...generateAddAssests(), ...generateDllReferences() ] }
# add-asset-html-webpack-plugin 用于把 dll 添加到 `index.html` 的 script 标签中 # glob 支持正则匹配文件 yarn add add-asset-html-webpack-plugin glob -D
utils.js
const webpack = require('webpack') const glob = require('glob') const AddAssestHtmlWebpackPlugin = require('add-asset-html-webpack-plugin') const generateDllReferences = function() { const manifests = glob.sync(`${resolve('dll')}/*.json`) return manifests.map(file => { return new webpack.DllReferencePlugin({ // context: resolve(''), manifest: file }) }) } const generateAddAssests = function() { const dlls = glob.sync(`${resolve('dll')}/*.js`) return dlls.map(file => { return new AddAssestHtmlWebpackPlugin({ filepath: file, outputPath: '/dll', publicPath: '/dll' }) }) }
-
добавить npm-скрипты
package.json
"scripts": { "dll": "webpack --config build/webpack.dll.conf.js" },
тогда вы можете использоватьyarn dll
Упакованные и настроенные глобальные общедоступные зависимости упакованы и будутsrc/dll
генерация каталога*dll.js
а также*dll.json
, первое зависит от сжатых и объединенных файлов (mode: production
), последний*dll.js
файл и исходный файл сопоставления зависимостей, которые раньше анализировались DllReferencePlugin для установления ссылок и*dll.js
картографические отношения между ними.
Два наиболее трудоемких шага в построении — это babel и сжатие, которые обычно игнорируются при настройке babel.node_modules
Таким образом, DllPlugin экономит время сжатия некоторых общедоступных зависимостей, поэтому, если вы не хотите использовать DllPlugin, вы также можетеexternals
настроить их как внешние зависимости, сжать и импортировать другими способами
Улучшите скорость сборки: создайте разумную исходную карту
В webpack 4 то, будет ли генерироваться исходная карта и каким образом, определяетсяdevtool
Для управления конфигурацией выбор разумной исходной карты может эффективно сократить время упаковки. Прежде чем выбирать, мы все же должны понимать, что упаковка является самой быстрой без настройки Source Map.Причина, по которой необходима Source Map, заключается в том, что структура кода и имя файла после упаковки полностью не соответствуют тем, что были до упаковки.При возникновении ошибки мы можем найти только напрямую.После упакованного файла невозможно найти исходный файл, что значительно увеличивает сложность отладки. Карта исходного кода предназначена для улучшения возможности отладки упакованного кода, поэтому она всегда нужна нам в среде разработки и имеет больше возможностей в производственной среде.
devtool
Дополнительная конфигурация сnone
,eval
,cheap-eval-source-map
Существует 13 видов, и их функции и производительность сравниваются вДокументацияподробно описаны.
Элемент конфигурации состоит из одного или нескольких слов и дефисов. Каждое слово имеет свое значение и снижает производительность. Окончательное значение каждого элемента конфигурации определяется следующими словами:
-
none
Не генерирует исходную карту, производительность +++ -
eavl
Каждый модуль состоит изeval
Выполнить, не может правильно отображать количество строк, не может использовать производственный режим, производительность +++ -
module
Ошибка отображения исходного кода, производительность - -
source
Ошибка отображения информации о строке и столбце, отображение перенесенного кода Babel, производительность -- -
cheap
Режим с низкими накладными расходами, без сопоставления столбцов, производительность + -
inline
Не создавать отдельный файл исходной карты, производительность o
среда разработки
Поскольку режим разработки рекомендует отображать исходный код ошибки и информацию о строке, поэтомуmodule
а такжеsource
нужны, а для производительности нам нужноeval
а такжеcheap
, поэтому обратившись к элементам конфигурации, вы сможете найти наиболее подходящую конфигурацию для среды разработки.devtool: cheap-module-eval-source-map
.
Производственная среда
Поскольку в производственной среде почти не требуется отладка (отладка, связанная с JS), рекомендуется установитьdevtool: none
, а затем измените настройку наdevtool: cheap-module-source-map
.
Повышение скорости сборки: другие оптимизации
Оптимизации, упомянутые в этом разделе, на самом деле почти все конфигурации по умолчанию в нашей предыдущей конфигурации.
JS многопоточное сжатие
Как упоминалось ранее, сжатие — это трудоемкая часть построения, поэтому мы можем включить многопоточное сжатие terser-webpack-plugin, чтобы сократить время сжатия.
module.exports = {
optimization: {
minimizer: [
new TerserJSPlugin({
parallel: true // 开启多线程压缩
})
]
}
}
область видимости и кэширование babel
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
// 不转译 node_modules
// exclude: [resolve('node_modules')]
// 转译 src 目录下的文件
include: [
resolve('src')
],
options: {
cacheDirectory: true // 默认目录 node_modules/.cache/babel-loader
// cacheDirectory: resolve('/.cache/babel-loader')
}
}
]
}
}
кеш vue-загрузчика
vue-loadercacheDirectory
Элементы конфигурации зависят от загрузчика кеша
yarn add cache-loader -D
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
use: {
loader: 'vue-loader',
options: {
prettify: false,
cacheDirectory: resolve('node_modules/.cache/vue-loader'),
cacheIdentifier: 'vue'
}
}
}
]
}
}
resolve.modules использует абсолютные пути
resolve.modules
Сообщает Webpack, в каких каталогах следует искать при разборе модулей, можно задать как относительные, так и абсолютные пути. При установке относительных путей, таких какresolve.modules: [node_modules]
, при разрешении зависимостей он будет искать из текущего каталога, пока не найдетnode_modules
содержание. Установка абсолютного пути может сократить этот процесс обхода и найти каталог напрямую.
module.exports = {
resolve: {
modules: [resolve('node_modules')]
}
}
Как я уже говорил, эта оптимизация лучше, чем ничего.
Используйте ES6
ES6 не только добавляет некоторые общие методы к исходным объектам, но также добавляет некоторые новые лексические и грамматические элементы для удобства разработчиков, что, естественно, не может отсутствовать в этом проекте. Однако разные браузеры и разные версии имеют непоследовательную поддержку ES6, что приводит к некоторым препятствиям для использования ES6.Нам нужно использовать babel-loader для преобразования лексики и синтаксиса ES6 в ES5.
Некоторое время назад я представил babel-loader/babel 7, поэтому не буду повторять введение здесь.руководство по использованию babel-loader
Использование EditorConfig и eslint
Очень важно согласовать стандарты кодирования для совместных проектов с участием нескольких человек, потому что это может эффективно повысить эффективность совместной работы и подавить рост гнева программистов. Конечно, я думаю, что личные проекты также нужны, потому что код 6-месячной давности такой же, как и код всех остальных.
EditorConfig
EditorConfig — это кросс-редакторное решение спецификации кода, поддерживаемое многими редакторами (поддержка реализации редактора или плагина), что означает, что разные редакторы могут форматировать код в одном стиле, например vscode и возвышенное. Метод конфигурации заключается в добавлении.editorconfig
Файл, некоторые редакторы могут быть сгенерированы командой в один клик, обычно конфигурация следующая:
.editorconfig
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false
-
root
Является ли это файлом конфигурации верхнего уровня, обычно установленным вtrue
Указывает, что файл конфигурации не будет продолжать искать файл конфигурации после поиска. -
indent_style
Отступ табуляции -
indent_size
Размер отступа, приведенный выше пример означает: отступ представлен двумя пробелами -
charset
Кодирование -
trim_trailing_whitespace
удалять ли завершающие пробелы -
insert_final_newline
заканчивается ли файл пустой строкой
eslint
Javascript — это динамический язык (язык со слабой типизацией), гибкий, но подверженный ошибкам, поэтому при совместной разработке необходимо сформулировать некоторые правила, чтобы гарантировать, что каждый участник выводит код в согласованном стиле. eslint — это инструмент с открытым исходным кодом для решения этой проблемы, вы можете установить правила, он проверит, является ли Javascript законным на основе правил, и вернет ошибку или предупреждение, если он не является законным.
-
Установить
yarn add eslint -D
-
Инициализировать файл конфигурации
npx eslint --init
Выберите необходимые пункты согласно подсказкам и установите соответствующий плагин и конфиг, мне также нужно установить здесь
eslint-config-standard
а такжеeslint-plugin-vue
yarn add eslint-config-standard eslint-plugin-vue -D
.eslintrc.js
module.exports = { "env": { "browser": true, "es6": true }, "extends": [ "plugin:vue/essential", "standard" ], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parserOptions": { "ecmaVersion": 2018, "sourceType": "module" }, "plugins": [ "vue" ], "rules": { } }
-
Настройте соответствующие правила в rules
Видетькитайский документ
Анализируйте информацию о пакетах с помощью webpack-bundle-analyzer
Иногда мы обнаруживаем, что размер некоторых спавнов неправильный, но в консоли трудно увидеть причину, в это время нам нужна помощь инструментов анализа модулей. Здесь я рекомендую использовать webpack-bundle-analyzer, который запустит службу и наглядно отобразит в браузере отношение сопоставления и иерархию между сгенерированными и исходными файлами, как показано на рисунке (рисунок взят с Github):
Установить
yarn add webpack-bundle-analyzer -D
использовать
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}
Оптимизация пользовательского опыта
Оптимизация взаимодействия с пользователем на уровне построения заключается в следующих аспектах: уменьшение размера генерируемого кода, разумные методы загрузки и разумное сокращение количества HTTP-запросов.В этом разделе основное внимание уделяется первым двум.
Уменьшите оптимизацию HTTP, о которой мы упоминали при использовании url-loader для обработки изображений.
Сжать CSS
Вебпак 4 дюймаproduction
В режиме код JS будет сжат по умолчанию, используйтеTerserWebpackPlugin, но CSS не будет (Webpack 5 делает это как встроенную функцию), поэтому нам нужноOptimizeCSSAssetsPluginс помощь.
Установить
yarn add optimize-css-assets-webpack-plugin -D
использовать
Большинство плагинов Webpack используются таким же образом, но использование этого плагина в Webpack 4 требует особого внимания, и при его использовании он будет переписан.optimization.minimizer
, а подключаемый модуль TerserWebpackPlugin для сжатия JS находится в значении по умолчанию для этой опции. Переопределение сделает значение по умолчанию недействительным, поэтому вам также необходимо явно объявить экземпляр TerserWebpackPlugin.
webpack.prod.conf.js
const TerserJSPlugin = require("terser-webpack-plugin")
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")
module.exports = {
optimization: {
minimizer: [
new TerserJSPlugin({
parallel: true // 开启多线程压缩
}),
new OptimizeCSSAssetsPlugin({})
]
}
}
Сжатие — это оптимизация в производственной среде, ее установка в среде разработки повлияет на производительность горячей загрузки и приведет к обратным результатам.
разделение кода
Разделение кода имеет два преимущества:
-
Удалите общий код и зависимости, чтобы избежать повторной упаковки
-
Избегайте слишком большого размера одного файла
Общий объем загрузки постоянен, и браузер обычно загружает несколько файлов быстрее, чем один файл.
Тест перед разлукой
Давайте сначала добавим в проект ресурсы, на которые будут ссылаться home и page-a:src/utils/index.js
& src/styles/main.styl
, а затем обратитесь к ним отдельно на двух страницах, чтобыpage-a.vue
Пример.
Для удобства проверки сгенерированного кода установимmode: development
получить несжатый код
page-a.vue
<template>
<div class="page-a">
<h1>
This is page-a
</h1>
</div>
</template>
<script>
import { counter } from '@/utils'
export default {
name: 'page-a',
created() {
counter()
console.log('page-a:', counter.count)
}
}
</script>
<style lang="stylus" scoped>
@import '~@/styles/main.styl';
.page-a {
background: blue;
}
</style>
воплощать в жизньyarn build
упакуем проект, и мыhome.vue
Соответствующий продукт (dist/css/views/home.[contentHash].css
а такжеdist/views/home.[contentHash].js.
), они содержатsrc/styles/main.styl
а такжеsrc/utils/index.js
желаемое содержимое в файле. Однако проверимpage-a.vue
Было обнаружено, что соответствующие сгенерированные объекты также содержат это содержимое, поэтому исходный код был упакован в сгенерированные объекты, соответствующие двум страницам.
Он упаковывается повторно, потому что эти две страницы ссылаются на них одновременно.При количестве цитирований 3, 10 и более эти общедоступные ресурсы (включая общедоступные зависимости) могут даже составлять более 95% генерируемого объема, что составляет явно недопустимо.
SplitChunksPlugin
Для решения проблемы повторной упаковки публичных ресурсов нам необходимоSplitChunksPluginС помощью он может разделить код на разные пакеты, которые загружаются, когда они нужны странице. Также SplitChunksPlugin — это встроенный плагин webpack 4, поэтому нам не нужно устанавливать его отдельно.
использовать
webpack.prod.conf.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 1, // 正常设置 20000+ 即 20k+ ,但这里我们的公共文件只有几行代码,所以设置为 1
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '/',
name(mod, chunks) {
return ${chunks[0].name}
},
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
}
воплощать в жизньyarn build
Упаковывая проект, мы видим, что толькоdist/views/home.[contentHash].js.
(или в отдельном JS) будет содержатьutils.js
содержание, при этомdist/views/page-a.[contentHash].js.
Только ссылки:_utils__WEBPACK_IMPORTED_MODULE_0__["counter"]
.
Изменить имя вывода
Мы можем использовать VSCode для отладки упакованного кода конфигурации ( nodejs ) и получитьname
в функцииmod / chunks
Структура объекта, согласно информации, возвращает нужное нам имя файла.
Конечно, вы также можете использовать-inspect
Приходитьотладкакод.
// 命名和代码分离息息相关,这里仅为使用示例,具体命名请根据项目情况更改
name(mod, chunks) {
if (chunks[0].name === 'app') return 'app.vendor'
if (/src/.test(mod.request)) {
let requestName = mod.request.replace(/.*\\src\\/, '').replace(/"/g, '')
if (requestName) return requestName
} else if (/node_modules/.test(mod.request)) {
return 'dependencies/' + mod.request.match(/node_modules.[\w-]+/)[0].replace(/node_modules./, '')
}
return null
}
Чаще всего задают магический комментарий для указания имени файла, а не задают его через функцию имени, потому что последняя часто отделяет какой-то код, который не должен отделяться
tree shaking
Выше мы разделили код, чтобы решить проблему, состоящую в том, что часть кода в проекте многократно упаковывается в несколько продуктов, эффективно уменьшая объем продуктов, но на самом деле мы можем еще больше уменьшить объем на этой основе, что включает в себя Сотрясение дерева концепций.
Встряхивание дерева — это термин, обычно используемый для описания удаления мертвого кода из контекста JavaScript. Он основан на статической структуре синтаксиса модулей ES2015, таких как импорт и экспорт.
Вы можете думать о приложении как о дереве. Зеленым цветом обозначены фактически используемые исходный код и библиотека, которые являются живыми листьями на дереве. Серый представляет код без ссылок, увядшие листья на деревьях осенью. Чтобы убрать опавшие листья, нужно встряхнуть дерево, чтобы они упали.
Оглядываясь назад на файлы, сгенерированные при использовании SplitChunksPlugin, мы видим, чтоsay
Функция не используется, но упакована, это фактически бесполезный код, который в документации мёртвый код. Чтобы удалить эти коды, просто введитеmode
превратиться вproduction
(Позвольте встряхиванию дерева подействовать), упаковать снова~
Однако следует отметить, что хотя встряхивание дерева может удалить бесполезный код, оно также имеет определенные побочные эффекты (ошибочное определение бесполезного кода). Например, вы можете столкнутьсяБиблиотека компонентов пользовательского интерфейса не имеет стилейПричина этой проблемы в том, что встряхивание дерева работает не только для JS, но и для CSS. Мы обычно используем при импорте CSSimport 'xxx.min.css'
, статический импорт производственной среды ES6 + удовлетворяет условиям для вступления в силу встряхивания дерева, и Webpack не может определить, что CSS действителен, поэтому он считается мертвым кодом, а затем удаляется. Чтобы решить эту проблему, вы можетеpackage.json
добавитьsideEffects
возможность сообщить Webpack, какие файлы можно импортировать без дрожания дерева, используя следующее:
package.json
{
"sideEffects": [
"*.css",
"*.styl(us)?"
]
}
загрузка ресурсов
Разумная загрузка ресурсов иногда важнее, чем уменьшение размера кода
нагрузка по требованию
Загрузка по требованию, также известная как отложенная загрузка, означает, что при открытии страницы, которая должна быть зависимой, загружается зависимость, что снижает нагрузку на домашнюю страницу и повышает скорость рендеринга первого экрана. А чтобы делать загрузку по требованию, нужно использовать только при импорте зависимостейimport()
илиrequire.ensure
Эти два метода динамической загрузки. мы добавляемlodash
Зависимость для тестирования:yarn add lodash
page-a.vue
// 静态加载
import _ from 'lodash'
// 懒加载
// import(/* webpackChunkName: "dependencies/lodash" */ 'lodash')
export default {
name: 'page-a',
created() {
console.log(_.now())
}
}
Запустите службу разработки в этот момент, и мы увидим, что, хотя здесь используется статическая загрузка, зависимость lodash будет загружена (отложенная загрузка) только после нажатия на страницу-a. Потому что мы уже использовали его, когда используем маршрут настройкиimport()
Динамическая загрузка (забыл об этом), поэтому статические ресурсы страницы-страницы тоже становятся ленивой загрузкой.
Давайте еще раз посмотрим на предыдущий оператор динамической загрузки.import(/* webpackChunkName: "views/home" */ '@/views/home/main.vue')
, есть момент знания, на который стоит обратить внимание/* webpackChunkName: "views/home" */
, это волшебная аннотация Webpack, здесь имя файла сгенерированного чанка, указанное волшебной аннотацией, поэтомуsrc/views/home/main.vue
Упакованный JS файла естьdist/views/home.[contentHash].js
.
предварительная загрузка, предварительная выборка
Выше упоминалось об использовании магических аннотаций для именования спавнов, на самом деле preload preload и prefetch prefetch также задаются с помощью magic аннотаций. Вот введение в их сходства и различия в официальной документации:
- Блок предварительной загрузки начинает загружаться параллельно, когда загружается родительский блок. Блок предварительной выборки начнет загружаться после завершения загрузки родительского блока.
- Блок предварительной загрузки имеет средний приоритет и загружается немедленно. Фрагмент предварительной выборки загружается, когда браузер бездействует.
Но в моем тесте и preload, и prefetch загружаются параллельно, но их приоритет будет ниже требуемых текущей страницей зависимостей и не повлияет на загрузку страницы. ты сможешьmain.js
Добавьте следующий код для проверки:
src/main.js
// 对比测试
// import 'lodash'
// 预加载
// import(/* webpackPreload: true, webpackChunkName: "dependencies/lodash" */ 'lodash')
// 预取
import(/* webpackPrefetch: true, webpackChunkName: "dependencies/lodash" */ 'lodash')
Поскольку результаты испытаний в этом разделе не соответствуют документам, надеюсь, вы сможете убедиться в этом сами и не верьте в пристрастность.
Особенно очевиден эффект от использования предварительной загрузки и предварительной выборки для работы с большими зависимостями, такими как диаграммы, редакторы форматированного текста.
внешние расширения
Иногда мы напрямую внедряем некоторые JS-библиотеки (например, lodash в этой статье) прямо в проект, а Webpack будет их парсить и сжимать. Но подумайте об этом, у самого lodash есть сжатая версия.lodash/lodash.min.js
, а его размер не слишком мал для слияния с другими JS (700k несжатого, 70k после сжатия), нам не имеет особого смысла его парсить и сжимать. так что мы можем положить его вstatic
папку (или CDN) и вindex.html
китайское использованиеscript
Импорт тегов, если проект импортировал lodash (import 'lodash'
) можно настроитьexternals
Игнорируйте это при упаковке, иначе не делайте этого.
Если вы хотите использовать здесьlink[ref=prefetch/preload]
preload, поэтому не забудьте повторно использовать его там, где это уместно.script
Введены теги, предварительная загрузка только для кеширования
-
новый
/static
папка, добавитьlodash.min.js
-
изменения кода
yarn add copy-webpack-plugin -D
/build/webpack.prod.conf.js
const CopyWebpackPlugin = require('copy-webpack-plugin') module.exports = { externals: { lodash: { commonjs: 'lodash', umd: 'lodash', root: '_' // 默认执行环境已经存在全局变量: _ ,浏览器中就是 window._ } }, plugins: [ new CopyWebpackPlugin([ { from: 'static/', to: 'static/' } ]) ] }
/src/main.js
import _ from 'lodash' console.log(_.now())
/index.html
<body> <script type="text/javascript" src="static/lodash.min.js"></script> </body>
Некоторые друзья могут подумать, что синтаксический анализ lodash может позволить Webpack узнать, какие функции не используются, а затем встряхнуть их, но на самом деле lodash не является статическим экспортом синтаксиса модуля ES6, поэтому встряхивание дерева не сработает. Если проект не сильно зависит от lodash, а использует лишь некоторые из этих функций, рекомендуется импортировать одну функцию следующим образом:
import now from 'lodash/now'
console.log(now())
module.noParse
Представленная в документации возможность также не включать упаковку некоторых модулей, но, к сожалению, на данный момент это не очень удобно. Потому что для эффективности нельзя ссылаться на соответствующие зависимости в коде, по сути, если ссылки нет, то она не будет записана в графе зависимостей, и естественно не будет упакована (поэтому этот пункт конфигурации ничего не делает ).