前言
上篇内容从零开始搭建webpack4的react项目,这里只说多页相关的配置。上篇文章地址:webpack4+react从零开始搭建项目
先看下多页的文件目录结构:

这里我们有一个公用的html模板,app1和app2的两个多页文件。
webpack.config.js
配置主要更改两个部分:
一、entry
里面是键值对结构:
module.exports = (env, argv) => {
return {
entry: {
app1: './src/app1/index.js',
app2: './src/app2/index.js'
}
}
}
看过我上篇的同学肯定会问,上篇不是数组嘛,还能加babel-polyfill
,所以也可以是这种配置:
module.exports = (env, argv) => {
return {
entry: {
entry: {
app1: ["babel-polyfill", './src/app1/index.js'],
app2: ["babel-polyfill", './src/app2/index.js']
}
}
}
二、plugins
里的new HtmlWebpackPlugin
变成数组形式:
module.exports = (env, argv) => {
return {
plugins: [
// ...
new HtmlWebpackPlugin({
chunks:['app1'], //添加引入的js,也就是entry中的key
filename:'app1.html', // 输出页面,如http://localhost:3000/app1.html就能看到第一个模板
hash:true,
title:'第一个页面',
template: './public/index.html' //模板地址
}),
new HtmlWebpackPlugin({
chunks:['app2'], //添加引入的js,也就是entry中的key
filename:'app2.html', // 输出页面
hash:true,
title:'第二个页面',
template: './public/index.html' //模板地址
})
]
}
}
简单配置完毕,如果想动态配置,可以这么改,直接贴出所有配置,主要是这两个函数:,我觉得怎么封装好理解是自己的事情,建议大家最好自己封装一套,最重要的方法就一个glob.sync('src/**/index.js')
获取src下第一层级文件夹下的index.js。
const webpack = require('webpack');//引入webpack
const path = require('path');//引入nodejs路径模块,处理路径用的
const glob = require('glob');//glob,这个是一个全局的模块,动态配置多页面会用得着
const HtmlWebpackPlugin = require('html-webpack-plugin'); //这个是通过html模板生成html页面的插件,动态配置多页面用得着
const CleanWebpackPlugin = require('clean-webpack-plugin'); // 清除打包的源文件,再打包,避免文件重复
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//分离css,webpack4推荐的分离css的插件
const autoprefixer = require('autoprefixer');//给css自动加浏览器兼容性前缀的插件
const os = require('os');//这个nodejs模块,会帮助我们获取本机ip
const portfinder = require('portfinder');//这个帮助我们寻找可用的端口,如果默认端口被占用了的话
const fs = require('fs');//处理文件用的
//动态加时间戳,发布不需要刷新浏览器
function stamp(){
var date = new Date();
date = Date.parse(date);
return date;
}
//端口占用动态+1
var ports = fs.readFileSync('./port.json', 'utf8');
ports = JSON.parse(ports);
portfinder.basePort = "3000";
portfinder.getPort(function(err, port) {
ports.data.port = port;
ports = JSON.stringify(ports,null,4);
fs.writeFileSync('./port.json',ports);
});
//获取本机ip
function getIPAdress(){
const interfaces = os.networkInterfaces();
for(let devName in interfaces){
const iface = interfaces[devName];
for(let i=0;i<iface.length;i++){
const alias = iface[i];
if(alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal){
return alias.address;
}
}
}
}
module.exports = (env, argv) => {
const devMode = argv.mode !== 'production'
const webpackConfig = {
entry: {},
output:{
path:path.resolve(__dirname, './dist/'),
filename:`[name]-${stamp()}.js`
},
//设置开发者工具的端口号,不设置则默认为3000端口
devServer: {
port: ports.data.port, //端口号
overlay: true, // 开启错误调试,
hot: true, //是否开启hot-module-replacement
https: false, // 如果需要用https请开启,如http2
compress:false, //是否启用 gzip 压缩。boolean 为类型,默认为 false
open: false, // 启动且第一次构建完时自动用你系统上默认的浏览器去打开要开发的网页。
stats: "errors-only", // 只展示错误信息,避免大量无用日志
host: getIPAdress() //获取本机器ip
},
module:{
rules:[
{
test:/\.(js|jsx)$/,
exclude:/node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [{
loader: "html-loader",
options: {
minimize: true
}
}]
},
{
test: /\.css$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
{
loader: "postcss-loader",
options: {
plugins: [
require("autoprefixer") /*在这里添加*/
]
}
}
]
},
{
test: /\.less$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
{
loader: "postcss-loader",
options: {
plugins: [
require("autoprefixer") /*在这里添加*/
]
}
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
},
plugins: [
new CleanWebpackPlugin(
['dist'],
{
root: __dirname,
verbose: true,
dry: false
}
),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
]
}
// 获取指定路径下的入口文件
function getEntries(globPath) {
const files = glob.sync(globPath),
entries = {};
files.forEach(function(filepath) {
const split = filepath.split('/');
const name = split[split.length - 2];
entries[name] = './' + filepath;
});
return entries;
}
const entries = getEntries('src/**/index.js');
Object.keys(entries).forEach(function(name) {
webpackConfig.entry[name] = entries[name]; // entry拼接对象键值对
const plugin = new HtmlWebpackPlugin({
filename: name + '.html',
template: './public/index.html',
inject: true,
chunks: [name]
});
webpackConfig.plugins.push(plugin); //new HtmlWebpackPlugin数组
})
return webpackConfig
};
这里多了三个方法:
1、动态加时间戳 stamp()
,如果我们发布不打tag,那么浏览器就有缓存,每次发布,就需要强刷页面,很可能被提成bug,这里可以添加时间戳,然后在output
方法里面加入即可
output:{
path:path.resolve(__dirname, './dist/'),
filename:`[name]-${stamp()}.js`
}
2、获取本机ip,我们之前看页面是localhost,如果想分享,就需要ipconfig,我们自动获取,方便了一些。
第一步根目录创建port.json
:
{
"data": {
"port": 3000
}
}
第二步在webpack.config.js
写好方法:
var ports = fs.readFileSync('./port.json', 'utf8');
ports = JSON.parse(ports);
portfinder.basePort = "3000";
portfinder.getPort(function(err, port) {
ports.data.port = port;
ports = JSON.stringify(ports,null,4);
fs.writeFileSync('./port.json',ports);
});
第三步webpack.config.js
配置devServer
devServer: {
port: ports.data.port, //端口号
3、获取本机ipgetIPAdress
,配置devServer
devServer: {
host: getIPAdress() //获取本机器ip
}
github地址:https://github.com/muyu-zhilu/webpack-react-multipage
网友评论