Commit 1640419b authored by 胖蔡's avatar 胖蔡

新增webpack多页面配置.

parent 5a3ff1f4
Pipeline #15635 canceled with stage
{
"eggHelper.serverPort": 53395
}
\ No newline at end of file
---
title: webpack 多页面配置
date: 2022/4/15 10:44:20
tags:
- webpack
- 多页面
- 构建工具
author: 蔡海飞
---
基于业务本身考虑,针对企业官网性质、面向C端用户的PC网站。我们需要有良好的搜索体验,需要有良好的页面访问体验。对此,探讨webpack配置多页面开发工程的可能性。本篇文章,默认大家对于webpack已经具有一定的了解,可以完成一些基础的webpack配置操作。如有不清楚的,请[点击查看](https://www.webpackjs.com/)
<!-- more -->
整体配置,我将其拆分为**5**个部分的配置。分别是:
- webpack.config.js
所有配置信息的整合合并配置,和基础的webpack配置。
- config/plugins.js
webpack的所有插件配置信息
- config/proxy.js
将webpack中的代理信息单独拿出来进行配置管理
- config/rules.js
webpack的加载器配置模块独立配置管理
- router.js
这是新增自定义的路由配置,由于自定义路由地址和指定配置路由文件。
### config/rules.js
> 本部分配置,主要是为了给工程提供更多的适配,如ts、less、scss、postcss等功能。
```
/* eslint-disable no-undef */
const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' );
const rules = [
{
test: /\.js$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [path.resolve( __dirname, 'src' )], // 指定检查的目录
options: { // 这里的配置项参数将会被传递到 eslint 的 CLIEngine
formatter: require( 'eslint-friendly-formatter' ), // 指定错误报告的格式规范
},
},
{
test: /\.[tj]s?$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.tsx?$/, exclude: /node_modules/, use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
],
},
{ test: /\.ts$/, exclude: /node_modules/, use: ['ts-loader'] },
{
test: /\.ejs$/, use: [
{
loader: 'ejs-loader',
options: {
esModule: false,
variable: 'data',
},
},
],
},
{
test: /\.(sa|sc|le|c)ss$/,
use: [
{
// 把js中import导入的样式文件,单独打包成一个css文件,结合html-webpack-plugin,以link的形式插入到html文件中。
loader: MiniCssExtractPlugin.loader,
// options: {
// publicPath: '../',//设置publicPath,解决css文件中background背景图片路径问题
// },
},
// 把js中import导入的样式文件打包到js文件中,运行js文件时,将样式自动插入到<style标签中,style-loader不能和mini-css-extract-plugin同时使用
// 'style-loader',
'css-loader',
'postcss-loader',
'less-loader',
'sass-loader',
],
},
{ test: /\.eot$|\.svg$|\.ttf$|\.woff$/, use: ['url-loader'], type: 'asset/resource', },
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
generator: {
filename: 'images/[name]_[hash]_[ext]'
},
},
{
test: /\.(csv|tsv)$/i,
use: ['csv-loader'],
},
{
test: /\.xml$/i,
use: ['xml-loader'],
},
]
module.exports = rules;
```
### config/plugins.js
这部分是用于完成webpack的插件配置工作的,我们这里提供了css合并分立插件、构建清空已有文件,最重要的是实现ejs模块化转html的工作。
```
/* eslint-disable no-undef */
const path = require('path'); // Node.js 处理文件路径的模块
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const glob = require('glob');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); // webpack 5.x 使用
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // minify extract js to css
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const router = require('./router');
const { routes } = router;
// const autoprefixer = require('autoprefixer');
// webpack.config.js 通用插件配置
const getHtmlWebpackPlugins = () => {
const mode = process.env.TEST_MODE || null;
console.log('get plugin mode:', mode)
if (mode && mode === 'template') {
// 模板测试
return glob.sync(path.resolve(__dirname, '../test/templates') + '/**/*.{jsx,ejs}').map(item => {
var prefixPath = path.resolve(__dirname, '..\/test\/templates');
var filePath = item.substring(prefixPath.length + 1, item.lastIndexOf('.'));
console.log('加载模板路径:', filePath);
return new HTMLWebpackPlugin({
template: item,
filename: filePath + '.html',
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联 css
},
favicon: './config/icon.png',
title: 'title',
chunks: ['common', 'test/'+filePath],
inject: true,
})
});
}
return routes.map(item => {
console.log('loading template info:', JSON.stringify(item));
const filename = item.path.lastIndexOf('\/') === String(item.path).length - 1 ? item.path + 'index.html' : item.path + ".html";
const chunks = ['common'];
if (item.main) {
chunks.push(item.path.substring(1));
}
console.log('get chunks:',chunks)
return new HTMLWebpackPlugin({
template: path.resolve(__dirname, '../src/templates/' + item.template),
filename:filename.substring(1),
minify: {
// 压缩 HTML 文件
removeComments: true, // 移除 HTML 中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联 css
},
favicon: './config/icon.png',
title: item.name,
chunks,
inject: true,
})
})
}
const plugins = [
new webpack.ProvidePlugin({ // 配置shim预置依赖
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default'],
// In case you imported plugins individually, you must also require them here:
Util: "exports-loader?Util!bootstrap/js/dist/util",
Dropdown: "exports-loader?Dropdown!bootstrap/js/dist/dropdown",
}),
require('autoprefixer'), // autoprefixer可以自动在样式中添加浏览器厂商前缀,避免手动处理样式兼容问题
new MiniCssExtractPlugin({
// 类似 webpackOptions.output里面的配置 可以忽略 css 文件分离
filename: 'css/[name].[chunkhash:8].css',
chunkFilename: '[id].css',
}),
new CssMinimizerPlugin(), // 配置css-minimizer-webpack-plugin
new webpack.DefinePlugin({
'process.env.build_lang': `"${process.env.build_lang}"`,
}),
// 如果不想在 watch 触发增量构建后删除 index.html 文件,可以在 CleanWebpackPlugin 中配置 cleanStaleWebpackAssets 选项 来实现
new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
...getHtmlWebpackPlugins(),
new webpack.HotModuleReplacementPlugin(),
]
module.exports = plugins;
```
### config/router.js
这里主要是路由的自定义配置,实现指定页面的指定js依赖的功能。
```
/* eslint-disable no-undef */
// 路由配置文件
const routes = [
{
path: '/index',
template: 'index.ejs',
name: '首页',
},
{
path: '/page/1',
template: 'page/1.ejs',
name: '测试页面',
main: '/pages/test.js',
},
]
module.exports = { routes };
```
### webpack.config.js
```
/* eslint-disable no-undef */
const path = require("path"); // Node.js 处理文件路径的模块
const glob = require("glob");
const plugins = require("./config/plugins"); // 配置插件
const rules = require("./config/rules"); // 加载器
const proxy = require("./config/proxy");
const router = require("./config/router");
const { routes } = router;
/**
* 入口文件
*/
const entries = function () {
const mode = process.env.TEST_MODE || null;
let map = {
common: ["@/app.js", "lodash"],
};
if (process.env.NODE_ENV === "development") {
map.hot = "webpack/hot/dev-server";
map.client = "webpack-dev-server/client/index.js?hot=true&live-reload=true";
}
if (mode && mode === "template") {
// 模板测试
// add test entries
glob
.sync(path.resolve(__dirname, "./test/templates") + "/**/*.{js,ts}")
.forEach((item) => {
let prefixPath = path.resolve(__dirname, "./test/templates");
let filePath = item.substring(
prefixPath.length + 1,
item.lastIndexOf("."),
);
console.log("loading module", filePath);
map["test/" + filePath] = item;
});
} else {
routes
.filter((item) => item.main)
.map((item) => {
const main = path.resolve(__dirname, "./src" + item.main);
console.log("loading entry file:", main);
map[item.path.substring(1)] = main;
});
}
return map;
};
module.exports = {
// 入口文件
// name: language, // 语言名称
entry: entries(),
watch: true,
watchOptions: {
poll: 1000, // 每秒询问多少次
aggregateTimeout: 500, //防抖 多少毫秒后再次触发
ignored: /node_modules/, //忽略时时监听
},
mode: process.env.NODE_ENV === "production" ? "none" : "development",
output: {
// 存放打包后的文件的位置
path: path.resolve(__dirname, "./dist"),
// 打包后的文件名
filename: "[name].bundle.[contenthash:8].js",
chunkFilename: "[name].js", // 代码拆分后的文件名
// clean: true,
// pathinfo: false,
publicPath: "/",
},
target: "web",
cache: {
type: "memory",
},
module: { rules: rules },
plugins: [
...plugins,
// new I18nPlugin(rq),
],
devServer: {
devMiddleware: {
index: true,
mimeTypes: { "text/html": ["phtml"] },
publicPath: "/dist",
serverSideRender: true,
writeToDisk: true,
},
static: "./dist",
proxy,
// publicPath: 'http://localhost:8080',
// port: 9000,
historyApiFallback: true,
compress: true,
hot: false,
client: false,
open: true, // when open is enabled, the dev server will open the browser.
},
resolve: {
extensions: [".ts", ".js", ".json"],
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
context: path.resolve(__dirname),
};
```
webpack.config.js是webpack打包的配置整合,可通过如上配置实现简单的多页面配置性编译,新增路由可通过在config/router.js中添加页面路由配置即可。
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment