用構建工具create-react-app初始化的項目默認是單頁應用,即整個項目只有一個入口文件和出口文件。但是在實際工作中,由於業務的需求,需要多頁面應用,這裏記錄一下如何修改create-react-app的默認配置來滿足多頁應用的開發。
1、在項目下執行yarn run eject(npm run eject)
此命令對項目工程是不可逆的,且只能執行一次。運行後,package.js會被更新,工程下會多出config目錄,其中有webpack有兩個配置文件,分別對應開發和生產環境(/config/webpack.config.dev.js和/config/webpack.config.prod.js)。這兩個配置文件都要修改,但略有不同,下面以dev爲例說明:
2、修改webpack配置支持多入口
- 修改config/paths.js文件
安裝globbyyarn add globby
//遍歷public下目錄下的html文件生成arry
const globby = require('globby');
const htmlArray = globby.sync([path.join(resolveApp('public'), '/*.html')]);
//module.exports 裏面增加
htmlArray
- 修改config/webpack.config.dev.js
要點:
- entry從原來的數組擴展爲對象,每個key代表一個入口;
- output中的filename要區分輸出名,可增加[name]變量,這樣會根據entry分別編譯出每個entry的js文件。
- Webpack配置多入口後,只是編譯出多個入口的JS,同時入口的HTML文件由HtmlWebpackPlugin生成,也需做配置。
chunks
,指明哪些webpack入口的JS會被注入到這個HTML頁面。如果不配置,則將所有entry的JS文件都注入HTML。filename
,指明生成的HTML路徑,如果不配置就是build/index.html,admin配置了新的filename,避免與第一個入口的index.html相互覆蓋。
// 遍歷html
const entryObj = {};
const htmlPluginsAray = paths.htmlArray.map((v)=> {
const fileParse = path.parse(v);
entryObj[fileParse.name] = [
require.resolve('./polyfills'),
require.resolve('react-dev-utils/webpackHotDevClient'),
`${paths.appSrc}/${fileParse.name}.js`,,
]
return new HtmlWebpackPlugin({
inject: true,
chunks:[fileParse.name],
template: `${paths.appPublic}/${fileParse.base}`,
filename: fileParse.base
})
});
<!--entry 替換爲entryObj-->
entry:entryObj
//出口增加[name]
output: {
path: paths.appBuild,
pathinfo: true,
filename: 'static/js/[name].js',
chunkFilename: 'static/js/[name].chunk.js',
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath),
},
<!--替換htmlplugin內容-->
// new HtmlWebpackPlugin({
// inject: true,
// chunks: ["index"],
// template: paths.appPublic + '/index.html',
// }),
...htmlPluginsAray,
- 修改config/webpackDevServer.config.js
上述配置做完後,理論就可以打包出多入口的版本;但使用npm start啓動後,發現無論輸入/index.html還是/admin.html,好像都是和原來/index.html顯示一樣的內容。甚至輸入顯然不存在的/xxxx.html,也顯示爲/index.html的內容。
這種現象,初步判斷是HTTP服務器把所有請求重定向到了/index.html。對於單頁應用,這種做法是沒有問題的(本來就一個頁面);但我們新增的/admin.html就不能訪問了。發現是webpack dev server的問題,還要額外做一些配置,需修改/config/webpackDevServer.config.js。
// 增加
const path = require('path');
const htmlPluginsAray = paths.htmlArray.map((v)=> {
const fileParse = path.parse(v);
return {
from: new RegExp(`^\/${fileParse.base}`), to: `/build/${fileParse.base}`
};
});
<!--historyApiFallback 增加 rewrites-->
rewrites: htmlPluginsAray
3、prod環境
- 修改config/webpack.config.prod.js,同開發環境。
- 修改scripts/build.js
增加複製模塊(yarn add cpy
)
//增加
const cpy = require('cpy');
// function copyPublicFolder () 替換
// 原來的方法是複製public下所有的內容,因爲增加了多html 所以不再直接複製過去(直接複製會覆蓋html)
const copyPublicFolder = async() => {
await cpy([`${paths.appPublic}/*.*`, `!${paths.appPublic}/*.html`], paths.appBuild);
console.log('copy success!');
// fs.copySync(paths.appPublic, paths.appBuild, {
// dereference: true,
// filter: file => file !== paths.appHtml,
// });
}