前言
上篇內(nèi)容從零開始搭建webpack4的react項(xiàng)目,這里只說多頁相關(guān)的配置。上篇文章地址:webpack4+react從零開始搭建項(xiàng)目
先看下多頁的文件目錄結(jié)構(gòu):
這里我們有一個(gè)公用的html模板,app1和app2的兩個(gè)多頁文件。
webpack.config.js
配置主要更改兩個(gè)部分:
一、entry
里面是鍵值對結(jié)構(gòu):
module.exports = (env, argv) => {
return {
entry: {
app1: './src/app1/index.js',
app2: './src/app2/index.js'
}
}
}
看過我上篇的同學(xué)肯定會問,上篇不是數(shù)組嘛,還能加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
變成數(shù)組形式:
module.exports = (env, argv) => {
return {
plugins: [
// ...
new HtmlWebpackPlugin({
chunks:['app1'], //添加引入的js,也就是entry中的key
filename:'app1.html', // 輸出頁面,如http://localhost:3000/app1.html就能看到第一個(gè)模板
hash:true,
title:'第一個(gè)頁面',
template: './public/index.html' //模板地址
}),
new HtmlWebpackPlugin({
chunks:['app2'], //添加引入的js,也就是entry中的key
filename:'app2.html', // 輸出頁面
hash:true,
title:'第二個(gè)頁面',
template: './public/index.html' //模板地址
})
]
}
}
簡單配置完畢,如果想動態(tài)配置,可以這么改,直接貼出所有配置,主要是這兩個(gè)函數(shù):,我覺得怎么封裝好理解是自己的事情,建議大家最好自己封裝一套,最重要的方法就一個(gè)glob.sync('src/**/index.js')
獲取src下第一層級文件夾下的index.js。
const webpack = require('webpack');//引入webpack
const path = require('path');//引入nodejs路徑模塊,處理路徑用的
const glob = require('glob');//glob,這個(gè)是一個(gè)全局的模塊,動態(tài)配置多頁面會用得著
const HtmlWebpackPlugin = require('html-webpack-plugin'); //這個(gè)是通過html模板生成html頁面的插件,動態(tài)配置多頁面用得著
const CleanWebpackPlugin = require('clean-webpack-plugin'); // 清除打包的源文件,再打包,避免文件重復(fù)
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//分離css,webpack4推薦的分離css的插件
const autoprefixer = require('autoprefixer');//給css自動加瀏覽器兼容性前綴的插件
const os = require('os');//這個(gè)nodejs模塊,會幫助我們獲取本機(jī)ip
const portfinder = require('portfinder');//這個(gè)幫助我們尋找可用的端口,如果默認(rèn)端口被占用了的話
const fs = require('fs');//處理文件用的
//動態(tài)加時(shí)間戳,發(fā)布不需要刷新瀏覽器
function stamp(){
var date = new Date();
date = Date.parse(date);
return date;
}
//端口占用動態(tài)+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);
});
//獲取本機(jī)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`
},
//設(shè)置開發(fā)者工具的端口號,不設(shè)置則默認(rèn)為3000端口
devServer: {
port: ports.data.port, //端口號
overlay: true, // 開啟錯(cuò)誤調(diào)試,
hot: true, //是否開啟hot-module-replacement
https: false, // 如果需要用https請開啟,如http2
compress:false, //是否啟用 gzip 壓縮。boolean 為類型,默認(rèn)為 false
open: false, // 啟動且第一次構(gòu)建完時(shí)自動用你系統(tǒng)上默認(rèn)的瀏覽器去打開要開發(fā)的網(wǎng)頁。
stats: "errors-only", // 只展示錯(cuò)誤信息,避免大量無用日志
host: getIPAdress() //獲取本機(jī)器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數(shù)組
})
return webpackConfig
};
這里多了三個(gè)方法:
1、動態(tài)加時(shí)間戳 stamp()
,如果我們發(fā)布不打tag,那么瀏覽器就有緩存,每次發(fā)布,就需要強(qiáng)刷頁面,很可能被提成bug,這里可以添加時(shí)間戳,然后在output
方法里面加入即可
output:{
path:path.resolve(__dirname, './dist/'),
filename:`[name]-${stamp()}.js`
}
2、獲取本機(jī)ip,我們之前看頁面是localhost,如果想分享,就需要ipconfig,我們自動獲取,方便了一些。
第一步根目錄創(chuàng)建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、獲取本機(jī)ipgetIPAdress
,配置devServer
devServer: {
host: getIPAdress() //獲取本機(jī)器ip
}
github地址:https://github.com/muyu-zhilu/webpack-react-multipage