前言
-
新生的CRA配置是
单页面
网页应用 -
出于某些目的,需要打包成多入口。比如
storybook
框架,多入口使用iframe
嵌套。 -
webpack版本
4.44.2
解决方案
-
需要用到两个文件
webpack.config.js
、paths.js
配置文件(没有的弹出cra配置) -
修改入口,新增一个
configuration
的入口
//原始入口
...
entry:
isEnvDevelopment && !shouldUseReactRefresh
? [
webpackDevClientEntry,
paths.appIndexJs,
]
: paths.appIndexJs
...
//修改入口,`paths.appConfigurationIndexJs`为你的新`index.js`入口文件地址
...
entry:
isEnvDevelopment && !shouldUseReactRefresh
? {
webpack: webpackDevClientEntry,
index: paths.appIndexJs,
configuration: paths.appConfigurationIndexJs,
}
: {
index: paths.appIndexJs,
configuration: paths.appConfigurationIndexJs,
},
...
- 修改网页插件
HtmlWebpackPlugin
,paths.appConfigurationHtml
为你的模版html,可以直接使用paths.appHtml
。此处新增后,生成的对应js文件会被动态分配到入口html
文件处
//原始内容
...
plugins: [
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
)
),
...
]
...
//修改为,可以改为动态获取,我此处作为演示
...
plugins: [
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appHtml,
chunks: ['index'], //新增项
filename: 'index.html' //新增项
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
),
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appConfigurationHtml,
chunks: ['configuration'],
filename: 'configuration.html'
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
),
...
]
...
- 修改
.map
插件,不修改此处运行会产生报错filter
找不到
...
new ManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: paths.publicUrlOrPath,
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path;
return manifest;
}, seed);
----------------------------------------------------------
//原始代码
const entrypointFiles = entrypoints.main.filter(
fileName => !fileName.endsWith('.map')
);
//新代码
const entrypointFiles = [];
Object.keys(entrypoints).map(entrypoint => {
if (entrypoint !== "webpack") { //抛弃webpack插入的入口
entrypointFiles[entrypoint] = entrypoints[entrypoint].filter(fileName =>
!fileName.endsWith('.map'));
}
});
----------------------------------------------------------
return {
files: manifestFiles,
entrypoints: entrypointFiles,
};
},
}),
...
- 最后,修改
output
隐藏坑
...
output: {
path: isEnvProduction ? paths.appBuild : undefined,
pathinfo: isEnvDevelopment,
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
----------------------------------------------
//旧代码
: isEnvDevelopment && 'static/js/.bundle.js',
//新代码
: isEnvDevelopment && 'static/js/[name].bundle.js',
----------------------------------------------
futureEmitAssets: true,
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
publicPath: paths.publicUrlOrPath,
devtoolModuleFilenameTemplate: isEnvProduction
? info =>
path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/')
: isEnvDevelopment &&
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
jsonpFunction: `webpackJsonp${appPackageJson.name}`,
globalObject: 'this',
},
...
- 最后
paths.appConfigurationHtml
和paths.appHtml
可以相同,也可以不相同看个人配置。paths.appConfigurationIndexJs
也是一个入口.本质与index
相同。iframe
加载嵌套第二个入口,即可提高加载过长问题与异步加载等。
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<React.StrictMode>
<div>入口2</div>
</React.StrictMode>,
document.getElementById('root')
);
PS
- 重复打包问题
多个入口使用相同的包
肯定会被打入两个入口。配置splitChunks
拆分即可解决这个问题。该方案只提供思路。正常情况cra会自动划分复合依赖,抽成一个js的。
//旧代码
...
splitChunks: {
chunks: 'all',
name: isEnvDevelopment,
},
...
//新代码
...
splitChunks: {
// chunks: 'all',
// name: isEnvDevelopment,
cacheGroups: {
// 通过正则匹配,将 react react-dom echarts-for-react 等公共模块拆分为 vendor
// 这里仅作为示例,具体需要拆分哪些模块需要根据项目需要进行配置
// 可以通过 BundleAnalyzerPlugin 帮助确定拆分哪些模块包
vendor: {
test: /[\\/]node_modules[\\/](react|react-dom|echarts-for-react)[\\/]/,
name: 'vendor',
chunks: 'all', // all, async, and initial
},
// 将 css|less 文件合并成一个文件, mini-css-extract-plugin 的用法请参见文档:https://www.npmjs.com/package/mini-css-extract-plugin
// MiniCssExtractPlugin 会将动态 import 引入的模块的样式文件也分离出去,将这些样式文件合并成一个文件可以提高渲染速度
// 其实如果可以不使用 mini-css-extract-plugin 这个插件,即不分离样式文件,可能更适合本方案,但是我没有找到方法去除这个插件
styles: {
name: 'styles',
test: /\.css|less$/,
chunks: 'all', // merge all the css chunk to one file
enforce: true
}
}
},
...
网友评论