先上目录图
依赖和插件
{
"name": "webpack-multiple-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest --watchAll",
"build": "webpack --config ./config/webpack.prod.js",
"dev": "webpack-dev-server --config ./config/webpack.dev.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@types/jquery": "^3.5.16",
"@types/swiper": "^6.0.0",
"animate.css": "^4.1.1",
"aos": "^2.3.4",
"axios": "^1.4.0",
"javascript-obfuscator": "^4.0.2",
"jquery": "^3.7.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^5.3.4",
"swiper": "^10.0.4",
"wowjs": "^1.1.3"
},
"devDependencies": {
"@babel/core": "^7.22.9",
"@babel/plugin-syntax-jsx": "^7.22.5",
"@babel/plugin-transform-react-jsx": "^7.22.5",
"@babel/plugin-transform-runtime": "^7.22.9",
"@babel/preset-env": "^7.22.9",
"@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "^7.22.5",
"@babel/runtime": "^7.22.6",
"@jest/globals": "^29.6.1",
"@types/jest": "^29.5.3",
"autoprefixer": "^10.4.14",
"babel-loader": "^9.1.3",
"cache-loader": "^4.1.0",
"core-js": "^3.31.1",
"css-loader": "^6.8.1",
"file-loader": "^6.2.0",
"html-loader": "^4.2.0",
"html-webpack-plugin": "^5.5.3",
"html-withimg-loader": "^0.1.16",
"javascript-obfuscator": "^4.0.2",
"jest": "^29.6.1",
"less": "^4.1.3",
"less-loader": "^11.1.3",
"mini-css-extract-plugin": "^2.7.6",
"postcss-loader": "^7.3.3",
"postcss-preset-env": "^9.0.0",
"progress-bar-webpack-plugin": "^2.1.0",
"speed-measure-webpack-plugin": "^1.5.0",
"style-loader": "^3.3.3",
"terser-webpack-plugin": "^5.3.9",
"thread-loader": "^4.0.2",
"ts-jest": "^29.1.1",
"ts-loader": "^9.4.4",
"ts-node": "^10.9.1",
"typescript": "^5.1.6",
"url-loader": "^4.1.1",
"webpack": "^5.88.1",
"webpack-bundle-analyzer": "^4.9.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"webpack-merge": "^5.9.0",
"webpack-obfuscator": "^3.5.1",
"webpackbar": "^5.0.2"
}
}
使用webpack的多入口来打包后生成多页面
webpack公共配置
//webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const SpeedMeasureWebpackPlugin = require("speed-measure-webpack-plugin");
const WebpackBar = require("webpackbar");
const ProgressBarWebpackPlugin = require("progress-bar-webpack-plugin");
const fs = require("fs");
let t = new Date();
let y = t.getFullYear() + "";
let m = t.getMonth() + 1 + "";
let d = t.getDate() + "";
let h = t.getHours() + "";
let s = t.getMinutes() + "";
var Version = y + m + d + h + s;
let entry = {};
let HtmlTemplate = [];
const dirs = fs.readdirSync(path.resolve(__dirname, "../src/pages"));
dirs.map((item) => {
fs.readdirSync(path.resolve(__dirname, `../src/pages/${item}`)).map((item2) => {
if (path.extname(item2)=='.js') {
let name = item2.substring(0, item2.lastIndexOf("."));
entry[name] = path.resolve(__dirname, `../src/pages/${item}/${name}.js`);
console.log(entry);
}
});
});
for (const key in entry) {
if (Object.hasOwnProperty.call(entry, key)) {
console.log(key);
HtmlTemplate.push(
new HtmlWebpackPlugin({
template: path.resolve(__dirname, `../src/public/index.html`),
filename: `./${key}.html`,
chunks: [key],
hash: true,
inject: true,
minify: {
removeComments: true, //移出注释
collapseWhitespace: true,
},
})
);
}
}
module.exports = {
//入口文件的配置项
entry,
//出口文件的配置项
output: {
path: path.resolve(__dirname, "../build"),
filename: "./js/[name].js?v=" + Version,
},
resolve: {
//省略后缀
extensions: [".js",".jsx", ".less"], //后缀名 可以根据需要自由增减
alias: {
"@": path.resolve(__dirname, "../src"),
},
symlinks: false,
},
cache: {
type: "filesystem", // 使用文件缓存
},
//模块:例如解读CSS,图片如何转换,压缩
module: {
rules: [
{
test: /\.ts$/, //test 指定的是规则生效的文件
use: [
"cache-loader",
{
// 配置加载器
loader: "babel-loader",
// 设置babel
options: {
presets: [
[
"@babel/preset-env", // 指定环境的插件,
{
// 配置位置
targets: {
// 要兼容的目标浏览器
chrome: "88",
},
corejs: "3", // 指定corejs的版本
useBuiltIns: "usage", //使用corejs版本为3,"usage"表示按需加载
},
],
],
},
},
"ts-loader",
], // 要使用的loader
exclude: /node_modeules/, // 要排除的文件
include: path.resolve(__dirname, "../src"),
},
{
test: /\.jsx$/, //已作为js扩展名这样类型的文件
exclude: /node_modules/, //排除node_modules文件夹
include: path.resolve(__dirname, "../src"),
use: {
loader: "babel-loader", //转换成es5
options: {
presets: ["@babel/preset-react"], //设置编译的规则
plugins: [
// 设置编译的插件
["@babel/plugin-transform-runtime"], //设置编译的规则
],
},
},
},
{
test: /\.js$/, //已作为js扩展名这样类型的文件
exclude: /node_modules/, //排除node_modules文件夹
include: path.resolve(__dirname, "../src"),
use: [
{
loader: "babel-loader", //转换成es5
options: {
presets: ["@babel/preset-env"], //设置编译的规则
plugins: [
// 设置编译的插件
["@babel/plugin-transform-runtime"], //设置编译的规则
],
},
},
],
},
{
//匹配哪些文件
test: /\.less$/,
exclude: /node_modeules/,
include: path.resolve(__dirname, "../src"),
//使用哪些loader进行处理
use: [
MiniCssExtractPlugin.loader,
"cache-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"],
},
},
},
"less-loader",
],
},
{
test: /\.(png|jpe?g|gif|jpg|webp)$/,
type: "asset/resource",
include: path.resolve(__dirname, "../src"),
generator: {
filename: "../images/[name][ext]",
outputPath: "./images",
},
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
},
},
},
{
test: /\.(mp3|mp4)$/i,
include: path.resolve(__dirname, "../src"),
type: "asset/resource",
generator: {
filename: "./media/[name][ext]",
},
},
{
test: /\.(ttf|eot|woff2)$/i,
type: "asset/resource",
include: path.resolve(__dirname, "../src"),
generator: {
filename: "fonts/[name][ext]",
},
},
{
// 处理html中的img
test: /\.html$/,
include: path.resolve(__dirname, "../src"),
generator: {
filename: "./images/[name][ext]",
},
use: [
{
loader: "html-withimg-loader",
},
],
},
{
// 打包其他资源
exclude: /\.(css|ts|js|jsx|html|json|less|png|jpg|gif|ttf|eot|woff2|svg|bin|mp3|mp4)$/,
loader: "file-loader",
options: {
outputPath: "./file",
name: "[name].[ext]",
},
},
],
},
performance: {
hints: "warning", // 枚举
maxAssetSize: 30000000, // 整数类型(以字节为单位)
maxEntrypointSize: 50000000, // 整数类型(以字节为单位)
assetFilter: function (assetFilename) {
// 提供资源文件名的断言函数
return assetFilename.endsWith(".css") || assetFilename.endsWith(".js");
},
},
//插件,用于生产模版和各项功能
plugins: [
...HtmlTemplate,
new MiniCssExtractPlugin({
filename: "./css/[name].css?v=" + Version, //输出的文件名字
}),
new SpeedMeasureWebpackPlugin(),
new WebpackBar(),
new ProgressBarWebpackPlugin(),
],
};
webpack 开发配置
const { merge } = require("webpack-merge");
const commonConfiguration = require("./webpack.common.js");
const path = require("path");
const app = require("express")();
// let prot = Math.floor(Math.random()*4000+1000)
module.exports = merge(commonConfiguration, {
mode: "development",
devServer: {
static: {
directory: path.join(process.cwd(), "build"),
},
host: "localhost",
compress: true,
port: 4100,
hot: true, // 开启热更新,
},
});
webpack生产配置 打包自动删除的插件调不好,索性自己写一个
const { merge } = require("webpack-merge");
const commonConfiguration = require("./webpack.common.js");
const TerserPlugin = require("terser-webpack-plugin");
const {resolve} = require('path');
const WebpackObfuscator = require('webpack-obfuscator');
const {ClearBuildDir} = require('./webpackTools.ts')
// 打包删除build目录
try {
ClearBuildDir(resolve(__dirname,'../build'))
} catch (error) {
console.log('build文件夹正被使用')
}
module.exports = merge(commonConfiguration, {
mode: "production",
// 去除死代码
optimization: {
usedExports: true,
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
mangle: true, // 开启变量名混淆
compress: {
drop_console: true,
drop_debugger: false,
pure_funcs: ["console.log"],
},
},
}),
],
},
plugins: [
new WebpackObfuscator ({
rotateStringArray: true ,// 打乱Unicode数组顺序
compact: true,
deadCodeInjection: true,
debugProtection: true,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
}, [])
],
});
打包自动删除 build
const fs = require('fs');
const path = require('path');
function ClearBuildDir(folderPath) {
if (fs.existsSync(folderPath)) {
fs.readdirSync(folderPath).forEach((file) => {
const curPath = path.join(folderPath, file);
if (fs.lstatSync(curPath).isDirectory()) {
ClearBuildDir(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(folderPath);
}
}
module.exports = { ClearBuildDir }
首页 index.js
import ReactDOM from "react-dom/client";
import React from "react";
import MapRouter from "../../router/mapRouter";
import "./index.less";
ReactDOM.createRoot(document.getElementById("root")).render(<MapRouter />);
首页 IndexPage.jsx
import React from "react";
import Header from "../../components/Header/Header";
import Footer from "../../components/Footer/Footer";
export default function IndexPage(props) {
return (
<div>
<Header/>
<button onClick={() => {props.history.push("/about"); }} >
JumpAbout
</button>
<Footer/>
</div>
);
}
路由配置MapRouter.js
import React from "react";
import { HashRouter, Switch, Route, Redirect } from "react-router-dom";
import IndexPage from "../pages/Index/IndexPage";
import AboutPage from "../pages/About/AboutPage";
export default function MapRouter() {
return (
<HashRouter>
<Switch>
<Route path="/index" component={IndexPage}></Route>
<Route path="/about" component={AboutPage}></Route>
<Redirect from="/" to="/index" exact></Redirect>
</Switch>
</HashRouter>
);
}
仅供参考 如果有错误的地方还请各位大佬不吝赐教,拜谢