美文网首页
CRA多入口集成

CRA多入口集成

作者: 板栗炖牛肉 | 来源:发表于2022-01-04 14:36 被阅读0次

前言

  • 新生的CRA配置是单页面网页应用

  • 出于某些目的,需要打包成多入口。比如storybook框架,多入口使用iframe嵌套。

  • webpack版本4.44.2

解决方案

  • 需要用到两个文件webpack.config.jspaths.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,
                },
...
  • 修改网页插件HtmlWebpackPluginpaths.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.appConfigurationHtmlpaths.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
                    }
                }
            },
...

相关文章

网友评论

      本文标题:CRA多入口集成

      本文链接:https://www.haomeiwen.com/subject/tdvqcrtx.html