react- scripts 中的一系列技術棧配置都 在使用create-react-app構建項目時並未開放,須要使用如下命令彈射到應用的頂層以供個性化,不過特別注意,整個過程是不可逆的 ,eject後就能夠看見熟悉的webpack配置目錄config。javascript
npm run eject
複製代碼
webpack 是什麼?歸根到底,webpack 就是一個.js 配置文件,你的架構好或壞 都體如今webpack.config.js這個配置裏。html
webpack配置中最重要也是必選的兩項是入口(Entry)和出口(Output)。入口的做用是告訴webpack從哪裏開始尋找依賴,而且編譯,出口則用來配置編譯後的文件儲存位置和文件名。java
經過觀察發現 entry 處 只配置了一個入口 paths.appIndexJs ,點進去能夠看見指向index.js。react
entry: [
// Include an alternative client for WebpackDevServer. A client's job is to
// connect to WebpackDevServer by a socket and get notified about changes.
// When you save a file, the client will either apply hot updates (in case
// of CSS changes), or refresh the page (in case of JS changes). When you
// make a syntax error, this client will display a syntax error overlay.
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// the line below with these two lines if you prefer the stock client:
// require.resolve('webpack-dev-server/client') + '?/',
// require.resolve('webpack/hot/dev-server'),
isEnvDevelopment &&
require.resolve('react-dev-utils/webpackHotDevClient'),
// Finally, this is your app's code:
paths.appIndexJs,
// We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh.
].filter(Boolean),
複製代碼
entry: './path/to/my/entry/file.js' //單個入口(簡寫)語法
entry: {
main: './path/to/my/entry/file.js' //對象語法
}
entry: { //多頁面應用程序
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
複製代碼
這裏能夠看出將 單個入口 改寫爲 對象語法 的多頁面應用程序就能夠達到多入口的目的。webpack
工程化 能夠用到 globby 的幫助 搜尋 src 目錄下的多頁面應用:web
// 引入 globby 模塊
const globby = require('globby');
// 入口文件路徑
const entriesPath = globby.sync([resolveApp('src') + '/*/index.tsx']);
複製代碼
經過遍歷 globby 得到的目錄數組 得到 多頁面 路徑入口文件:npm
function getEntries(){
const entries = {};
const files = paths.entriesPath;
files.forEach(filePath => {
let tmpArr = filePath.split('/');
let name = tmpArr[tmpArr.length - 2];
entries[name] = [
filePath,
];
isEnvDevelopment && entries[name].push(require.resolve('react-dev-utils/webpackHotDevClient'));
//這份代碼是由react官方的create-react-app提供的熱構建插件
});
return entries;
}
複製代碼
咱們一般須要這個插件HtmlWebpackPlugin
自動處理,目前代碼是這樣:數組
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appHtml,
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
),
複製代碼
配置 HtmlWebpackPlugin 插件, 指定入口生成對應的 html 文件,有多少個頁面就須要 new 多少個 HtmllWebpackPlugin webpack配置多入口後,只是編譯出多個入口的JS,同時入口的HTML文件由HtmlWebpackPlugin生成,也需作配置。 chunks,指明哪些 webpack入口的JS會被注入到這個HTML頁面。若是不配置,則將全部entry的JS文件都注入HTML。 filename,指明生成的HTML路徑,若是不配置就是build/index.html,須要 配置新的filename,避免與第一個入口的index.html相互覆蓋。bash
咱們已經 經過 globby 的幫助拿到多入口對象 entries,這裏能夠遍歷處理:架構
const htmlPlugin = Object.keys(entries).map(item => {
return new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appHtml,
filename: item + '.html',
chunks: [item]
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
);
});
複製代碼
將 處理完成的 htmlPlugin 放入對應的 plugins,這裏能夠使用擴展運算符( spread ):
plugins: [
...htmlPlugin,
如下代碼省略...
複製代碼
如此能正常的打包出正確的 多頁面應用了,可是開發環境會受到靜態資源名字沒有Hash 而出現白屏,須要將 出口(Output)開發環境靜態資源加上 Hash值:
output: {
// The build folder.
path: isEnvProduction ? paths.appBuild : undefined,
// Add /* filename */ comments to generated require()s in the output.
pathinfo: isEnvDevelopment,
// There will be one main bundle, and one file per asynchronous chunk.
// In development, it does not produce real files.
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/[name].bundle.js',
// TODO: remove this when upgrading to webpack 5
futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
如下代碼省略...
複製代碼