Vue2 Webpack深度定制:Loader/Plugin开发与多页面优化
Vue2 进阶场景:Webpack 深度定制与优化实践
1. 自定义 Loader/Plugin 扩展 Webpack 功能
1.1 自定义 Loader 实现 Markdown 解析
Webpack Loader 本质是一个函数,接收源文件内容并返回处理后的结果。下面实现一个将 Markdown 转换为 Vue 组件的 Loader:
// markdown-loader.js
const marked = require('marked');
const hljs = require('highlight.js');
module.exports = function(source) {
// 配置marked
marked.setOptions({
highlight: (code, lang) => {
return hljs.highlight(lang, code).value;
}
});
// 将markdown转为HTML
const html = marked(source);
// 返回Vue组件格式
return `
<template>
<div class="markdown">${html}</div>
</template>
<script>
export default {
name: 'MarkdownViewer'
}
</script>
<style>
.markdown {
line-height: 1.6;
}
/* 添加代码高亮样式 */
pre code.hljs {
border-radius: 4px;
padding: 1em;
}
</style>
`;
};
配置使用:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.md$/,
use: [
'vue-loader',
path.resolve(__dirname, './markdown-loader.js')
]
}
]
}
}
实践建议:
- 优先使用社区成熟 Loader(如
markdown-it-loader
),自定义 Loader 适用于特殊需求 - 保持 Loader 功能单一,遵循单一职责原则
- 处理大文件时考虑使用缓存(
this.cacheable()
)
1.2 自定义 Plugin 实现构建通知
Plugin 通过钩子机制扩展 Webpack 功能。下面实现一个构建完成通知的 Plugin:
class BuildNotifyPlugin {
apply(compiler) {
compiler.hooks.done.tap('BuildNotifyPlugin', stats => {
const time = stats.endTime - stats.startTime;
const notifier = require('node-notifier');
notifier.notify({
title: 'Webpack 构建完成',
message: `耗时 ${time}ms`,
sound: true
});
// 同时输出到控制台
console.log(`构建完成,耗时 ${time}ms`);
});
}
}
配置使用:
// webpack.config.js
module.exports = {
plugins: [
new BuildNotifyPlugin()
]
}
2. 多页面应用(MPA)配置
2.1 基础多页面配置
Vue 默认是 SPA(单页应用),但通过 Webpack 可配置为 MPA:
// webpack.config.js
const glob = require('glob');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 动态获取入口文件
function getEntries(pattern) {
const entries = {};
glob.sync(pattern).forEach(file => {
const name = path.basename(file, path.extname(file));
entries[name] = file;
});
return entries;
}
const entries = getEntries('./src/pages/*/main.js');
module.exports = {
entry: entries,
output: {
filename: 'js/[name].[contenthash:8].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
...Object.keys(entries).map(name =>
new HtmlWebpackPlugin({
template: `./src/pages/${name}/index.html`,
filename: `${name}.html`,
chunks: [name],
minify: true
})
)
]
};
目录结构示例:
src/
pages/
home/
main.js
index.html
App.vue
about/
main.js
index.html
App.vue
2.2 共享公共代码
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 2,
minSize: 0
},
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
}
实践建议:
- 每个页面应有独立的入口文件和根组件
- 使用
chunks
配置精确控制每个页面加载的资源 - 长期缓存考虑使用
contenthash
命名文件
3. SSR 支持配置
3.1 基础 SSR 配置
// webpack.ssr.config.js
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');
module.exports = {
target: 'node',
entry: './src/entry-server.js',
output: {
filename: 'server-bundle.js',
libraryTarget: 'commonjs2'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
}
}
}
]
},
plugins: [
new VueSSRServerPlugin()
]
};
客户端配置:
// webpack.client.config.js
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin');
module.exports = {
entry: './src/entry-client.js',
plugins: [
new VueSSRClientPlugin()
]
};
3.2 服务端渲染流程
实践建议:
- 区分客户端和服务端特有的代码(如 DOM 操作)
- 使用
bundleRenderer
实现流式渲染提升性能 - 注意组件生命周期钩子的差异(服务端只有
beforeCreate
和created
)
4. 性能分析与优化
4.1 使用 webpack-bundle-analyzer
// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: 'report.html',
openAnalyzer: false
})
]
}
4.2 优化策略
代码分割:
// 动态导入路由组件 const UserDetails = () => import('./views/UserDetails.vue');
图片优化:
{ test: /\.(png|jpe?g|gif|webp)(\?.*)?$/, use: [ { loader: 'url-loader', options: { limit: 4096, // 4KB以下转base64 name: 'img/[name].[hash:8].[ext]', quality: 85 // 图片质量 } } ] }
Gzip 压缩:
const CompressionPlugin = require('compression-webpack-plugin'); module.exports = { plugins: [ new CompressionPlugin({ test: /\.(js|css|html|svg)$/, threshold: 10240 // 大于10KB的文件才压缩 }) ] }
实践建议:
- 定期运行分析工具监控包体积变化
- 优先优化最大的依赖项
- 考虑使用
externals
排除不常更新的库(如 Vue 本身)
总结
通过自定义 Loader/Plugin、MPA 配置、SSR 支持和性能分析,可以充分发挥 Vue2 在 Webpack 中的潜力。关键点在于:
- 定制化:根据项目需求扩展 Webpack 功能
- 优化:持续监控和优化构建结果
- 平衡:在开发体验和构建性能间找到平衡点
实际项目中,建议将这些技术点逐步引入,避免一次性过度优化带来的复杂性。
评论已关闭