React-CRA 多页面配置(react-app-rewired)

更新时间:2019-01-11
版本信息:CRA v2.1.1 + Webpack v4.19.1 + react-app-rewired v1.6.2

1、前言

为何要进行多页面配置

在使用 React 进行开发的过程当中,咱们一般会使用 create-react-app 脚手架命令来搭建项目,避免要本身配置 webpack,提升咱们的开发效率。可是使用 create-react-app 搭建的项目是单页面应用,若是咱们是作中后台管理页面或 SPA,这样是知足要求的,但若是项目有多入口的需求,就须要咱们进行一些配置方面的修改。javascript

通常如今有两种方式将脚手架搭建的项目修改成多入口编译:css

  1. 执行 npm run eject 命令,弹出配置文件,进行自定义配置。请参见:React-CRA 多页面配置(npm run eject)
  2. 使用 react-app-rewired 修改脚手架配置,在项目中安装 react-app-rewired 后,能够经过建立一个 config-overrides.js 文件来对 webpack 配置进行扩展。

本文对第 2 种方法给出具体配置方案,第 1 种方案详见:React-CRA 多页面配置(npm run eject)。在阅读本文以前,能够先了解一下第 1 种方案,有助于更好的理解本文内容。html

webpack 基础

本文对 React 多页面应用配置的探讨是基于使用 create-react-app 脚手架命令构建的项目,并非 webpack 多页面配置教程。但上述两种方案都应该具备必定的 webpack 的基础,实际上当你决定要改造或加强项目的构建打包配置的时候,你应该先对 webpack 进行必定的了解。java

若是你以前使用 webpack v3.x 版本,这里附上 webpack v4.0.0 更新日志 以及 webpack4升级彻底指南node

方案说明

经过使用 react-app-rewired 能够修改脚手架配置,从而实现扩展 webpack 配置,如增长对 less 文件的支持、增长 antd 组件的按需加载、处理 html 文档中的图片路径问题等,甚至能够将单页面入口编译修改成多页面入口编译的方式。react

咱们能够经过 react-app-rewired 在不暴露配置文件的状况下达到扩展项目配置的目的,一样咱们也能够经过 react-app-rewired 来实现多页面入口编译的配置,可是这须要对脚手架原来的配置具备必定了解的,相较于 npm run eject 暴露配置文件的方式来讲,这种方式是不太具备透明度的,后面维护的难度较大。本文的意义更多的是记录对这种方案的尝试,若是须要进行多页面配置,最好仍是先了解一下经过执行 npm run eject 暴露配置文件的方案,具备了必定的多页面配置经验和 webpack 使用经验以后再使用这种方案。webpack

本文方案完成的基础是,我以前已经经过 npm run eject 这种方式改造过一次多页面的配置,至关于说已经拆过这个箱子了,基本上了解了这个箱子里有什么,所以本文方案的配置实际上是对照着 npm run eject 这个方案中的配置文件来逐步进行的。git

版本的变更

使用 CRA 脚手架命令生成的项目免去了咱们本身配置 webpack 的麻烦,其内置的各类配置所须要的插件和依赖包的版本都是肯定的,是通过了检验的成熟配置,不会由于其中某个依赖包版本的问题形成构建出错。但当咱们决定要本身动手配置 webpack 的时候,就意味着咱们要本身根据须要安装一些 plugin 或 npm 依赖包,而这些插件和依赖包的版本可能不适用于当前 CRA 的版本,从而形成构建过程当中出现一些不可预期的错误。github

所以,咱们须要查看 CRA 脚手架项目的 package.json 文件,对于其中已经列出的 dependencies 依赖包,咱们不该该改变这些依赖包的版本,而对于未列出的 npm 包,咱们在使用的过程当中须要逐个验证,不要一次性安装不少个 npm 包,不然执行构建命令的时候若是出错就会很难排查,最好是根据咱们须要的功能逐个的安装相应的 npm 包,肯定没有问题,再进行下一个功能的扩展。web

正是因为版本的变更会对配置产生很大的影响,所以当咱们肯定了一个配置方案以后,不要再轻易去改动其中涉及到的 npm 包的版本,经过 package-lock.json 文件锁定版本,防止配置方案错乱。

另外,在本文编辑的时候,CRA 的最新版本为 v2.1.2,这个版本的 CRA 生成的项目,当前版本的 react-app-rewired v1.6.2 已经没法使用,具体信息能够参见 CRA >=2.1.2 breaking issue 2.1.2。至少在本文编辑的时候(2019.01.05),是没法适用于 CRA >=2.1.2 版本的,所以本文方案是基于最后一个能够适用的 CRA v2.1.1 版原本作的,package.json 文件中其余的 version 信息会附在方案后面。

2019-01-11 补充:上面提到的版本基本都是指 package.json 文件中列出的依赖包的版本,可是严格来说还应包含一些构建配置中使用的 node.js 工具包,好比 globbydir-glob等,这些工具包的版本更新也有可能会形成构建出错。这种状况的出现每每是没法预期的,它们形成的影响通常比较普遍,而不只仅是出如今咱们方案配置的过程当中,这种错误基本上都会在 Github 上有相应的 issue 以及解决方法或修复措施,本文中也列出了遇到的一个这种类型的错误,详见 4、错误排查 章节中的 其余错误 一节。

2、准备工做

建立一个 CRA v2.1.1 项目

咱们的配置方案是基于 CRA v2.1.1 脚手架项目进行改造的,所以首先咱们要先建立一个 CRA 项目,详见官方文档:Create React App

可是这样建立出来的项目默认是最新版本的 CRA 项目,咱们在上文中已经说明,咱们的配置方案是要求特定版本的 CRA 项目的,那么如何建立特定的 CRA v2.1.1 版本项目?

CRA 项目版本的核心其实就是 react-scripts 的版本,咱们能够先建立一个最新版本的脚手架项目,而后更改成 v2.1.1 版本,具体以下:

  1. 建立一个最新版本的 CRA 项目,参见官方文档:Create React App
  2. 删除 node_modules 文件夹,若是有 package-lock.json 文件或 yarn.lock 文件,也要一并删除,不然从新安装 node_modules 依赖包仍然会被锁定为原来的版本;
  3. 修改 package.json 文件,从新指定 react-scripts 的版本:

    "dependencies": {
      - "react": "^16.7.0",
      + "react": "^16.6.3",
      - "react-dom": "^16.7.0",
      + "react-dom": "^16.6.3",
      - "react-scripts": "2.1.3"
      + "react-scripts": "2.1.1"
    }
  4. 执行 yarn installnpm install 从新安装项目依赖。

至此,咱们已经建立了一个 CRA v2.1.1 项目,这将做为咱们进行多页面入口编译改造的基础。

react-app-rewired 的用法

首先要学习 react-app-rewired 的用法,参照官方文档:How to rewire your create-react-app project
主要是三点:

  1. 安装 react-app-rewired
  2. 建立一个 config-overrides.js 文件
  3. 修改 package.json 文件中的脚本命令

查看 CRA 项目原有的配置文件

上面咱们提到在进行多页面配置以前,须要对脚手架原有的配置文件具备必定了解,那么如何查看原有的配置文件?

  • 方法1:将使用 CRA 脚手架命令生成的项目拷贝一份,执行 npm run eject 暴露配置文件,eject 以后文件组织结构以下:

    my-app
    ├── config
    │   ├── jest
    │   ├── env.js
    │   ├── paths.js
    │   ├── webpack.config.dev.js
    │   ├── webpack.config.prod.js
    │   └── webpackDevServer.config.js
    ├── node_modules
    ├── public
    ├── scripts
    │   ├── build.js
    │   ├── start.js
    │   └── test.js
    ├── package.json
    ├── README.md
    └── src

    其中 config 文件夹下就是脚手架原有的配置文件。

  • 方法2:使用 CRA 脚手架命令生成项目,在 my-app/node_modules/react-scripts/config 路径下能够看到原有的配置文件
  • 方法3:在 config-overrides.js 文件中将 webpack 配置对象输出在控制台,查看其结构

推荐使用第 1 种方式,便于咱们在配置过程当中查看和操做,第 3 种方式做为一种辅助手段,主要是用于改造过程当中的调试和验证配置对象的改造结果的。

项目文件组织结构

在开始进行多入口配置以前,须要先明确项目的文件组织结构,这关系到咱们如何准确获取全部的入口文件,这里再也不详述,请参见React-CRA 多页面配置(npm run eject)中的项目文件组织结构一节。

3、具体方案

  1. 安装 react-app-rewired,建立 config-overrides.js 文件,修改 package.json 文件中的脚本命令。详见官方文档 How to rewire your create-react-app project

    执行 yarn start 命令,查看 http://localhost:3000,确保安装 react-app-rewired 操做没有问题。

  2. 修改文件组织结构。这里再也不详述,参见上文 项目文件组织结构 一节。
    CRA项目原文件组织结构为:

    my-app
      ├── README.md
      ├── node_modules
      ├── package.json
      ├── config-overrides.js // 安装 react-app-rewired 时建立的
      ├── .gitignore
      ├── public
      │   ├── favicon.ico
      │   ├── index.html
      │   └── manifest.json
      └── src
          ├── App.css
          ├── App.js
          ├── App.test.js
          ├── index.css
          ├── index.js
          ├── logo.svg
          └── serviceWorker.js

    修改成多页面入口编译的文件组织结构:

    // 本方案示例项目有两个页面 index.html & admin.html
      // 这里给出的文件组织结构是配置完成后的完整结构, 有些文件(如 src/setupProxy.js)的具体做用后面会给出说明
      my-app
      ├── README.md
      ├── node_modules
      ├── package.json
      ├── config-overrides.js // 安装 react-app-rewired 时建立的
      ├── .gitignore
      ├── public
      │   ├── favicon.ico
      │   ├── index.html // 做为全部页面的 html 模板文件
      │   └── manifest.json
      └── src
          ├── index.js // 空白文件, 为了不构建报错, 详见下文
          ├── setupProxy.js // proxy 设置, 详见下文(在当前操做步骤中能够缺失)
          ├── index // index.html 页面对应的文件夹
          │   ├── App.less
          │   ├── App.js
          │   ├── App.test.js
          │   ├── index.less // 使用 less 编写样式文件
          │   ├── index.js
          │   ├── logo.svg
          │   └── serviceWorker.js
          └── admin // admin.html 页面对应的文件夹
              ├── App.less
              ├── App.js
              ├── App.test.js
              ├── index.less // 使用 less 编写样式文件
              ├── index.js
              ├── logo.svg
              └── serviceWorker.js

    执行 yarn start 命令,查看 http://localhost:3000/index.html 和 http://localhost:3000/admin.html,确保修改文件组织结构操做没有问题。

    这个示例项目是以 my-app/public/index.html 做为全部页面的 html 模板文件的,固然也能够分别指定不一样的 html 模板文件,这是根据项目须要和项目文件组织结构决定的。在这个示例项目中,因为做为模板的 html 文件只须要有个根元素便可,所以将其做为全部入口的 html 模板文件。这样的话,每一个页面的 <title></title> 就须要在各自页面中分别指定,通常能够在页面挂载以后进行操做,好比:

    class App extends Component {
        componentDidMount() {
          document.title = 'xxx';
        }
        render() {
          return (
            ...
          );
        }
      }
  3. 修改 config-overrides.js 文件,进行具体配置。实际上咱们以后全部的操做都是在这个文件中进行的。
    咱们的测试方案是一个使用了 Ant Design、Redux、Less、Echarts 的多页面项目,须要达到如下要求:

    • 指定页面的多入口文件路径以及入口文件对应的 html 模板
    • 实现 antd 组件的按需加载
    • 增长对 less 文件的支持
    • 更改输出的文件名
    • 增长对 html 文档中图片路径的处理
    • 更改代码拆分的配置
    • 设置别名路径

上述每个功能的实现,都须要执行 yarn startyarn build 进行验证,确保操做成功后再进行下一项的配置。这里再也不逐步说明配置的步骤,详见下面的代码及注释。

最终 config-overrides.js 文件内容以下:

/* config-overrides.js */
  /*
  * @Author: mzhang.eric 
  * @Last Modified time: 2019-01-10 18:37:17
  * @Description: 使用 react-app-rewired 扩展和改造 CRA v2.1.1 项目, 基于 webpack v4.19.1  + react-app-rewired v1.6.2 版本
  */

  const rewireLess = require('react-app-rewire-less');
  const { injectBabelPlugin, paths } = require('react-app-rewired');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const path = require('path');
  const fs = require('fs');
  const globby = require('globby');
  const appDirectory = fs.realpathSync(process.cwd());
  const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
  // const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

  module.exports = function override(config, env) {

    // 使用 babel-plugin-import 按需加载组件
    config = injectBabelPlugin(
      ['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }],
      config,
    );

    // 增长 less 支持
    config = rewireLess.withLoaderOptions({
      // 解决报错: Inline JavaScript is not enabled. Is it set in your options?
      javascriptEnabled: true,
    })(config, env);

    // 入口文件路径
    // const entriesPath = globby.sync([resolveApp('src') + '/*/index.js']);
    const entriesPath = globby.sync([resolveApp('src') + '/*/index.js'], {cwd: process.cwd()});
    paths.entriesPath = entriesPath;

    // 获取指定路径下的入口文件
    function getEntries(){
      const entries = {};
      const files = paths.entriesPath;
      files.forEach(filePath => {
        let tmp = filePath.split('/');
        let name = tmp[tmp.length - 2];
        if(env === 'production'){
          entries[name] = [
            require.resolve('./node_modules/react-scripts/config/polyfills.js'),
            filePath,
          ];
        } else {
          entries[name] = [
            require.resolve('./node_modules/react-scripts/config/polyfills.js'),
            require.resolve('react-dev-utils/webpackHotDevClient'),
            filePath,
          ];
        }
      });
      return entries;
    }

    // 入口文件对象
    const entries = getEntries();

    // 配置 HtmlWebpackPlugin 插件, 指定入口文件生成对应的 html 文件
    let htmlPlugin;
    if(env === 'production'){
      htmlPlugin = Object.keys(entries).map(item => {
        return new HtmlWebpackPlugin({
          inject: true,
          template: paths.appHtml,
          filename: item + '.html',
          chunks: [item],
          minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeRedundantAttributes: true,
            useShortDoctype: true,
            removeEmptyAttributes: true,
            removeStyleLinkTypeAttributes: true,
            keepClosingSlash: true,
            minifyJS: true,
            minifyCSS: true,
            minifyURLs: true,
          },
        });
      });
    } else {
      htmlPlugin = Object.keys(entries).map(item => {
        return new HtmlWebpackPlugin({
          inject: true,
          template: paths.appHtml,
          filename: item + '.html',
          chunks: [item],
        });
      });
    }

    if (env === 'production') {
      for (let i = 0; i < config.plugins.length; i++) {
        let item = config.plugins[i];

        // 更改输出的样式文件名
        if (item.constructor.toString().indexOf('class MiniCssExtractPlugin') > -1) {
          item.options.filename = 'static/css/[name].css?_v=[contenthash:8]';
          item.options.chunkFilename = 'static/css/[name].chunk.css?_v=[contenthash:8]';
        }

        // SWPrecacheWebpackPlugin: 使用 service workers 缓存项目依赖
        if(item.constructor.toString().indexOf('function GenerateSW') > -1){
          // 更改输出的文件名
          item.config.precacheManifestFilename = 'precache-manifest.js?_v=[manifestHash]';
        }
      }

      // 更改生产模式输出的文件名
      config.output.filename = 'static/js/[name].js?_v=[chunkhash:8]';
      config.output.chunkFilename = 'static/js/[name].chunk.js?_v=[chunkhash:8]';

    } else {
      // 更改开发模式输出的文件名
      config.output.filename = 'static/js/[name].js';
      config.output.chunkFilename = 'static/js/[name].chunk.js';
    }

    // 修改入口
    config.entry = entries;

    // 修改 HtmlWebpackPlugin 插件
    for (let i = 0; i < config.plugins.length; i++) {
      let item = config.plugins[i];
      if (item.constructor.toString().indexOf('class HtmlWebpackPlugin') > -1) {
        config.plugins.splice(i, 1);
      }
    }

    config.plugins.push(...htmlPlugin);

    // 分析打包内容
    // config.plugins.push(new BundleAnalyzerPlugin());

    // 设置别名路径
    config.resolve.alias = {
      ...config.resolve.alias,
      '@src': paths.appSrc, // 在使用中有些 Eslint 规则会报错, 禁用这部分代码的 Eslint 检测便可
    };

    // 处理 html 文档中图片路径问题
    config.module.rules[2].oneOf.push({
      test: /\.html$/,
      loader: 'html-withimg-loader'
    });

    // 修改 build/static/media/ 路径下的文件名
    for (let i = 0; i < config.module.rules[2].oneOf.length; i++) {
      const item = config.module.rules[2].oneOf[i];
      if(!item.options || !item.options.name){ 
        continue;
      }
      let str = item.options.name.toString();
      if(str.indexOf('static/media/[name].[hash:8].[ext]') > -1){
        item.options.name = 'static/media/[name].[ext]?_v=[hash:8]';
      }
    }

    // 修改代码拆分规则,详见 webpack 文档:https://webpack.js.org/plugins/split-chunks-plugin/#optimization-splitchunks
    config.optimization = {
      splitChunks: {
        // 将全部入口点共同使用到的、次数超过 2 次的模块,建立为一个名为 commons 的代码块
        // 这种配置方式可能会增大初始的捆绑包,好比有些公共模块在首页其实并未用到,但也会打包进来,会下降首页的加载性能
        // 建议将非必需模块使用 import() 的方式动态加载,提高页面的加载速度
        // cacheGroups: {
        //   commons: {
        //     name: 'commons',
        //     chunks: 'initial',
        //     minChunks: 2
        //   }
        // }

        // 将全部使用到的 node_modules 中的模块包打包为 vendors 代码块。(不推荐)
        // 这种方式可能会产生一个包含全部外部依赖包的较大代码块,建议只包含核心框架和工具函数代码,其余依赖项动态加载
        // cacheGroups: {
        //   commons: {
        //     test: /[\\/]node_modules[\\/]/,
        //     name: 'vendors',
        //     chunks: 'all'
        //   }
        // }

        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
          }
        },
      },
    };

    return config;
  };

4、错误排查

这里对方案造成过程当中遇到的错误进行记录,这些错误有些是配置过程当中一定会出现的,是须要咱们进行改造的,也有些错误多是操做不当主观形成的。

客观错误

这类错误是进行多页面入口编译改造过程当中一定会遇到的,有些是因为项目文件组织结构的改变形成的,也有些是为了扩展项目配置而使用了源 CRA 脚手架项目未提供的 npm 包形成的,前者会出现哪些错误咱们是能够明确知道的,后者相对来讲是不确切的,但大多都是版本不适用形成的。

  1. Could not find a required file.

    Could not find a required file.
    Name: index.js
    Searched in: C:xxxxxxmy-appsrc

    错误描述:经过 create-react-app 脚手架搭建的项目以 my-app/src/index.js 做为应用入口,当执行构建脚本时若是检测到缺失了这个必要文件,node 进程会退出。可是在咱们进行多页面入口改造的时候,src 直接路径下没有 index.js 文件,根据咱们的文件组织结构,index.js 文件存在于每一个独立页面的子文件夹下,如 my-app/src/index/index.js my-app/src/admin/index.js
    解决方法:在 src 直接路径下建立一个空的 index.js 文件。

  2. Inline JavaScript is not enabled. Is it set in your options?

    // https://github.com/ant-design...
    .bezierEasingMixin();^ Inline JavaScript is not enabled. Is it set in your options?
    in C:xxxsrcmy-appnode_modulesantdesstylecolorbezierEasing.less (line 110, column 0)

    错误描述:less、less-loader 配置问题,提示须要容许行内 js 的执行,好比当咱们在项目中使用 antd 组件时,若是引入的样式文件是 less 文件,构建时就会报上述错误。
    解决方法:在 config-overrides.js 文件中增长 less 文件支持时,设置 javascriptEnabled 为 true。

    module.exports = function override(config, env) {
        ...
        // 增长 less 支持
        config = rewireLess.withLoaderOptions({
          // 解决报错: Inline JavaScript is not enabled. Is it set in your options?
          javascriptEnabled: true,
        })(config, env);
        ...
        return config;
      };
  3. Failed to load resource: net::ERR_FILE_NOT_FOUND(build 版本)

    错误描述:执行 yarn buildnpm run build 构建生产版本时,构建出的页面未能正确加载样式和脚本文件,chrome 检查工具报路径错误。
    解决方法:修改 package.json 文件,指定 homepage 字段的值,本项目这里指定为相对路径。

    "homepage": "./",
  4. When specified, "proxy" in package.json must be a string.

    When specified, "proxy" in package.json must be a string.
    Instead, the type of "proxy" was "object".
    Either remove "proxy" from package.json, or make it a string.

    错误描述:咱们在开发过程当中通常会在 package.json 文件中配置 proxy 代理服务器,可是在 CRA 2.x 升级之后对 proxy 的设置作了修改,具体请参见官方升级文档:Move advanced proxy configuration to src/setupProxy.js
    解决方法:移除 package.json 文件中有关 proxy 的设置,使用 http-proxy-middleware,在 src 目录下建立 setupProxy.js 文件。详细方法请参见上述文档。

主观错误

这类错误应该是能够避免的,可是在配置过程当中可能会因为开发人员的不当操做形成出错,最主要的就是安装了错误版本的 plugin 或 npm 包,咱们上面已经说过,对于项目本来的配置中在 package.json 文件中已经列出的 plugin 和 npm 包,不要再重复进行安装,不然可能从新安装的 plugin 或 npm 包版本是不适用的,从而形成出错。

例如,CRA v2.1.1 脚手架项目原有的 html-webpack-plugin 版本是 v4.0.0-alpha.2,是不须要再另外进行安装的。若是此时开发人员本身执行了 yarn add html-webpack-plugin,从而将 html-webpack-plugin 的版本更换为了 v3.2.0,这就会形成构建报错:URIError: Failed to decode param '/%PUBLIC_URL%/favicon.ico' URIError: Failed to decode param '/%PUBLIC_URL%/manifest.json',其余主观错误相似。

  1. html-webpack-plugin 版本错误

    URIError: Failed to decode param '/%PUBLIC_URL%/favicon.ico'
    URIError: Failed to decode param '/%PUBLIC_URL%/manifest.json'

    错误描述:在执行 yarn start 构建命令时报错,页面空白。
    解决方法:html-webpack-plugin 版本错误,在本文的配置方案中,应当使用 "html-webpack-plugin": "4.0.0-alpha.2", 版本。

  2. TypeError: Cannot read property 'state' of undefined(页面报错)

    错误描述:编译构建过程没有报错,但页面报错:TypeError: Cannot read property 'state' of undefined。
    解决方法:redux 版本错误,在本文的配置方案中,应当使用 redux <=3.7.2 版本。

其余错误

咱们在上文 版本的变更 一节的补充中已经对此有所说起,这类错误主要是由 node.js 工具包版本的升级形成的,这些错误基本都是不可预期的,也没法在这里所有涵盖,只能就当前遇到的问题进行简要记录,可能随着时间的推移,还会出现其余的相似问题,也可能这些错误已经在后续的版本中被修复了,所以请勿纠结于这里记录的错误,若是遇到了这类错误,就查阅资料进行修正,若是没有遇到,则无须理会。

  1. TypeError: Expected cwd to be of type string but received type undefined

    C:xxxmy-appnode_modulesdir-globindex.js:59
    throw new TypeError( Expected \cwd` to be of type `string` but received type `${typeof opts.cwd}``);
    TypeError: Expected cwd to be of type string but received type undefined

    错误描述:本文的写做开始于 2019-01-05,在 2019-01-11 从新审核本文方案的时候,遇到了这个错误,主要是因为 dir-glob 版本的升级形成的,咱们在配置脚本中使用了 globby 的 sync 方法,dir-glob 版本升级以后,这个方法的调用会使得 dir-glob 抛出上述错误。详细信息参见:Broken build do to major change from 2.0 to 2.2 以及 globby will pass opts.cwd = undefined to dir-glob, which leads to TypeError.

    解决方法:这里给出的解决方法是限定于当前时间的,由于在本文编辑的时候(2019-01-11)这个 issue 尚未给出最终的解决方案,我的以为可能会由 globby 进行修复。

    /* config-overrides.js */
    // 修改获取入口文件路径的代码
    // const entriesPath = globby.sync([resolveApp('src') + '/*/index.js']);
    const entriesPath = globby.sync([resolveApp('src') + '/*/index.js'], {cwd: process.cwd()});

5、package.json 信息

本文的多页面配置方案是基于 CRA 脚手架项目的,项目的依赖包信息会包含在两个 package.json 文件中,其中脚手架自带的配置信息位于 my-app/node_modules/react-scripts/package.json 文件中,而咱们根据项目须要本身增长的配置信息在 my-app/package.json 文件中,这里将本方案项目配置信息附录以下:

/* package.json */
  {
    "name": "my-app",
    "version": "0.1.0",
    "private": true,
    "dependencies": {
      "antd": "^3.12.1",
      "babel-plugin-import": "^1.11.0",
      "echarts": "^4.2.0-rc.2",
      "echarts-for-react": "^2.0.15-beta.0",
      "html-withimg-loader": "^0.1.16",
      "http-proxy-middleware": "^0.19.1",
      "react": "^16.6.3",
      "react-app-rewire-less": "^2.1.3",
      "react-app-rewired": "^1.6.2",
      "react-dom": "^16.6.3",
      "react-intl": "^2.7.2",
      "react-lazyload": "^2.3.0",
      "react-loadable": "^5.5.0",
      "react-redux": "^6.0.0",
      "react-scripts": "2.1.1",
      "redux": "3.7.2",
      "redux-promise-middleware": "^5.1.1",
      "webpack-bundle-analyzer": "^3.0.3"
    },
    "scripts": {
      "start": "react-app-rewired start",
      "build": "react-app-rewired build",
      "test": "react-app-rewired test --env=jsdom",
      "eject": "react-scripts eject"
    },
    "eslintConfig": {
      "extends": "react-app"
    },
    "browserslist": [
      ">0.2%",
      "not dead",
      "not ie <= 11",
      "not op_mini all"
    ],
    "homepage": "./"
  }
相关文章
相关标签/搜索