В этой статье около 2000 слов, на прочтение этой статьи уйдет около 20 минут, а на ее опробование — час.
Некоторое время назад я сделал проект, стек технологий vue + webpack, в основном домашняя страница официального сайта плюс система управления фоном. По ситуации на тот момент были проанализированы три варианта
- Два спа-приложения (официальный сайт и фоновая система) встроены в код проекта
- Разделите два набора исходного кода проекта
- Набор исходных кодов проекта содержит spa-приложение
считать:
- Напрямую отрицает спа-приложение в наборе исходного кода проекта (стили пользовательского интерфейса будут перезаписывать друг друга, если нет спецификации кода, его будет сложно поддерживать позже)
- При наличии двух наборов исходного кода в фоне может быть открыто два порта, и тогда использование nginx в качестве обратного прокси может оказаться проблематичным, а фронтенд-разработка еще более проблематичной, ведь два git-репозитория и необходимо поддерживать два набора онлайн-процессов git, что может занять много времени.
- Я (слепо) уверен в собственной технологии и хочу ее попробовать, проанализировать потребности не очень сложно. Выбран первый вариант, то есть несколько отдельных страниц применяются в наборе исходного кода.
Предыдущая схема многостраничной структуры
скачать шаблон vue spa
npm install vue-cli -g
vue init webpack multiple-vue-amazing
Модернизация многостраничных приложений
npm install glob --save-dev
Измените структуру каталогов в папке src
Добавьте в util.js
/* 这里是添加的部分 ---------------------------- 开始 */
// glob是webpack安装时依赖的一个第三方模块,还模块允许你使用 *等符号, 例如lib/*.js就是获取lib文件夹下的所有js后缀名的文件
var glob = require('glob')
// 页面模板
var HtmlWebpackPlugin = require('html-webpack-plugin')
// 取得相应的页面路径,因为之前的配置,所以是src文件夹下的pages文件夹
var PAGE_PATH = path.resolve(__dirname, '../src/pages')
// 用于做相应的merge处理
var merge = require('webpack-merge')
//多入口配置
// 通过glob模块读取pages文件夹下的所有对应文件夹下的js后缀文件,如果该文件存在
// 那么就作为入口处理
exports.entries = function () {
var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
var map = {}
entryFiles.forEach((filePath) => {
var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
map[filename] = filePath
})
return map
}
//多页面输出配置
// 与上面的多页面入口配置相同,读取pages文件夹下的对应的html后缀文件,然后放入数组中
exports.htmlPlugin = function () {
let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
let arr = []
entryHtml.forEach((filePath) => {
let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
let conf = {
// 模板来源
template: filePath,
// 文件名称
filename: filename + '.html',
// 页面模板需要加对应的js脚本,如果不加这行则每个页面都会引入所有的js脚本
chunks: ['manifest', 'vendor', filename],
inject: true
}
if (process.env.NODE_ENV === 'production') {
conf = merge(conf, {
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'dependency'
})
}
arr.push(new HtmlWebpackPlugin(conf))
})
return arr
}
/* 这里是添加的部分 ---------------------------- 结束 */
файл webpack.base.conf.js
/* 修改部分 ---------------- 开始 */
entry: utils.entries(),
/* 修改部分 ---------------- 结束 */
файл webpack.dev.conf.js
/* 注释这个区域的文件 ------------- 开始 */
// new HtmlWebpackPlugin({
// filename: 'index.html',
// template: 'index.html',
// inject: true
// }),
/* 注释这个区域的文件 ------------- 结束 */
new FriendlyErrorsPlugin()
/* 添加 .concat(utils.htmlPlugin()) ------------------ */
].concat(utils.htmlPlugin())
файл webpack.prod.conf.js
/* 注释这个区域的内容 ---------------------- 开始 */
// new HtmlWebpackPlugin({
// filename: config.build.index,
// template: 'index.html',
// inject: true,
// minify: {
// removeComments: true,
// collapseWhitespace: true,
// removeAttributeQuotes: true
// // more options:
// // https://github.com/kangax/html-minifier#options-quick-reference
// },
// // necessary to consistently work with multiple chunks via CommonsChunkPlugin
// chunksSortMode: 'dependency'
// }),
/* 注释这个区域的内容 ---------------------- 结束 */
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
/* 该位置添加 .concat(utils.htmlPlugin()) ------------------- */
].concat(utils.htmlPlugin())
Внедрить стороннюю библиотеку пользовательского интерфейса
npm install element-ui bootstrap-vue --save
Внедрите разные интерфейсы на разных страницах index.js
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue)
admin.js
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
Конфигурация вышеупомянутых нескольких страниц основана на Интернете, и идеи в Интернете в основном похожи.Ядро состоит в том, чтобы изменить несколько записей.После завершения конфигурации во время разработки не может быть обнаружено никаких проблем, и тогда это будет разрабатывался около месяца.После разработки При анализе производительности официального веб-сайта было обнаружено, что время загрузки в сети vendor.js, упакованного webpack, было очень долгим, что привело к очень долгому времени белого экрана на первом экране. Наконец, вывод был получен с помощью анализа -webpack-bundle-analyzer.
npm run build --report
Вы обнаружите, что vendor.js содержит общие части index.html и admin.html, поэтому этот пакет вендора обречен быть очень большим и избыточным.
Решения
Поскольку поставщик слишком велик, чтобы замедлить скорость загрузки, рекомендуется отделить поставщика. Я думал так: извлеките сторонний код, используемый на каждой странице, в vendor.js, а затем упакуйте сторонний код, используемый на каждой странице, в свой собственный vendor-x.js, например существующий индекс страницы .html, admin.html, vendor.js, vendor-index.js, vendor-admin.js в конечном итоге будут упакованы.
файл webpack.prod.conf.js
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor-admin',
chunks: ['vendor'],
minChunks: function (module, count) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0 &&
module.resource.indexOf('element-ui') != -1
)
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor-index',
chunks: ['vendor'],
minChunks: function (module, count) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0 &&
module.resource.indexOf('bootstrap-vue') != -1
)
}
}),
Еще раз анализ, все ок, vendor.js разделен на vendor.js,vendor-index,vendor-admin.js
Я думал, что проблема с отделением vendor.js от CommonsChunkPlugin решена, а потом распаковал и обнаружил, что импортированы и index.html, и admin.html (соответствующий vendor-xx.js)решение
Эта проблема на самом деле является проблемой HtmlWebpackPlugin. Измените исходный chunksSortMode: 'dependency' на конфигурацию пользовательской функции следующим образом.
файл util.js
chunksSortMode: function (chunk1, chunk2) {
var order1 = chunks.indexOf(chunk1.names[0])
var order2 = chunks.indexOf(chunk2.names[0])
return order1 - order2
},
Извлеките модуль common-api, общий для нескольких страниц.(2018/4/23)Обновлено
На самом деле, в сценарии извлечения общих файлов между несколькими страницами средние и крупные проекты будут использовать больше.Сначала я увидел комментарий ниже, что когда нужно извлечь common-api, больше common-api.css будет упаковано, и некоторые студенты Личное сообщение Я столкнулся с некоторыми проблемами с commonChunk, я сделаю обновление и предложу идеи
Требования: Некоторые общие js и даже css в проекте могут быть повторно использованы на каждой странице, например, admin.js относится к common-api.js, а index.js также относится к common-api.js. Теперь извлеките модуль common-api, общий для нескольких страниц.
добавить общий каталог
Создайте новый файл common/index.js и напрямую ссылайтесь на локальный файл js (здесь я использую jquery вместо общедоступного js)
Ссылаясь на общедоступные документы
Упоминается в admin.js index.js
import $ from '../../common'
console.log($('body'))
Пакетирование, очевидно, может обнаружить, что jquery упакован дважды, и ресурсы тратятся впустую.
решение
- Поскольку он многостраничный, необходимо добавить общедоступную запись common-api.
- commonChunkPlugin Извлечь common-api (есть ямки, о которых речь пойдет ниже)
- Изменить порядок фрагментов htmlWebpackPlugin
Яма в том, что чанки должны быть указаны, иначе будет сообщено об ошибке webpack ERROR в CommonsChunkPlugin: при работе в обычном режиме не разрешено использовать чанк без входа
В начале одноклассник спросил меня, как решить эту ошибку, я сначала не знал, но проверив некоторую информацию, обнаружил, что эту ошибку можно решить, указав чанки.Разместите раздел проблем с github, если вам интересно, вы можете узнать о нем больше.
Повторно укажите порядок htmlPlugin в util.js
let chunks = filename === 'admin' ?
['manifest', 'vendor', 'vendor-admin', 'common-api', filename] :
['manifest', 'vendor', 'vendor-index', 'common-api', filename]
Наконец, глядя на результаты, common-api извлекается, jq загружается только один раз, а common-api.css больше не запаковывается, порядок скриптов в html тоже правильный
наконец понял- Каждая страница загружает свой фрагмент
- Каждая страница имеет разные параметры
- Каждая страница может иметь общий фрагмент
- Кэширование браузера для повышения производительности
- Если он все еще слишком медленный, включите gzip.
- Каждая страница извлекает общедоступную функцию common-api (Обновлено 23 апреля 2018 г.)
впечатление
Вы закончили, хотя конфигурация выглядит очень простой, но я долго думал об этом, когда занимался разработкой, поэтому, если вы не знакомы с CommonsChunkPlugin и HtmlWebpackPlugin или используете только другие сторонние таблицы конфигурации, предполагается, что вы наступите на большую яму, например, CommonsChunkPlugin Если чанки не указаны, что по умолчанию? Большинство людей в minChunks могут только записывать значение, но способ написания пользовательской функции на самом деле самый мощный.Согласно моему личному опыту, фрагменты в сочетании со способом написания пользовательской функции в minChunks могут решить почти все сверхъестественные события Плагин CommonsChunk.
webpack4
Хоть эта статья и основана на webpack3, но идея многостраничной конфигурации и оптимизированной упаковки webpack4 на самом деле такая же.Используйте ее с уверенностью и решите, если есть яма.
исходный код
Исходный код этой статьинравится нравится