如何使用Webpack对React进行React Native-style多版本构建

时间:2017-10-12 19:55:35

标签: reactjs webpack

动机

我正在维护一个针对众多独立品牌的白色标签应用程序,这些应用程序主要在风格上有所不同,但有时也在核心用户体验中。当前(Backbone)解决方案涉及将共享代码保存在单独的仓库中,然后使用Grunt构建单独的应用程序,其中包含大部分样式代码以及生成在其自己的文件夹中的每个项目的一些视图覆盖。我们使用shell脚本一个接一个地运行所有grunt任务。我们将在React中继续构建此版本的新版本,并希望最大限度地减少重复代码,现在这已成为旧版本中的主要问题。

期望的结果

React Native包装程序同时构建其应用程序的两个版本。它会查看import ComponentA from './ComponentA.js'之类的导入语句,并首先查找ComponentA.android.jsComponentA.ios.js,如果找不到平台,则会返回导入ComponentA.js特定的一个。我想在Webpack中复制这种行为。所以我想有一个看起来像这样的文件夹:

react_clients/src/components
  |_ ComponentB.js // import ComponentA from './ComponentA.js';
  |_ ComponentA.js
  |_ ComponentA.brand1.js
  |_ ComponentA.brand2.js

Webpack应该构建ComponentB.js,如下所示:

  • brand1.bundle.jsComponentA.brand1.js
  • 导入
  • brand2.bundle.jsComponentA.brand2.js
  • 导入
  • brand3.bundle.jsbrand4.bundle.jsComponentA.js
  • 导入

这也适用于样式,理想情况下使用相同的命名约定。

如果需要,可以使用不同的webpack.config文件或接受命令行参数为每个版本单独运行Webpack。关键是要避免重复应用程序代码。

当前代码

Webpack的起点是一个新生成并弹出的create-react-app项目。

PS:如果事实证明是重复的话,请提前道歉但这对研究来说是一个非常棘手的问题。我怀疑答案将与https://webpack.js.org/configuration/resolve/的高级配置有关但尚无法解决。

1 个答案:

答案 0 :(得分:1)

好人们,我最终做了什么:

<强>开发

.env.development中,我为我想要开发项目的名称指定一个变量:

REACT_APP_VERSION_NAME=brand1

然后在webpack.config.dev.js中,我利用模块分辨率来实现上述行为:

const JS_PROJECT_EXTENSION = `.${process.env.REACT_APP_VERSION_NAME}.js`;
const STYLE_PROJECT_EXTENSION = `.${process.env.REACT_APP_VERSION_NAME}.pcss`;
const extensions = [JS_PROJECT_EXTENSION, '.js', '.json', '.jsx', STYLE_PROJECT_EXTENSION, '.pcss'];

...
module.exports = {
...
  extensions,
...
}

然后在代码中我可以简单地执行以下操作:

import ComponentA from './componentA';
import Styles from './styles';

一切都按预期工作。

<强>生产

我没有在REACT_APP_VERSION_NAME中指定.env.production。相反,相关的配置文件导出函数,我迭代我想要构建的版本。

首先,我创建了一个单独版本的config/paths.js导出函数而不是静态对象:

module.exports = function(projectName) {
  return {
    ...
    appBuild: resolveApp('build/' + projectName),
    ...
  };
}

我的webpack.config.prod.js看起来像这样:

...
const getPaths = require('./paths.prod');
...

module.exports = function(projectName) {
  const paths = getPaths(projectName);

  const JS_PROJECT_EXTENSION = `.${projectName}.js`;
  const STYLE_PROJECT_EXTENSION = `.${projectName}.pcss`;
  const extensions = [JS_PROJECT_EXTENSION, '.js', '.json', '.jsx', STYLE_PROJECT_EXTENSION, '.pcss'];

  ...
  return {
    ...
    output: {
      ...
      filename: projectName + '-assets/js/[name].[chunkhash:8].js',
      chunkFilename: projectName + '-assets/js/[name].[chunkhash:8].chunk.js',
      ...
    }
    ... [etc, adding projectName to any output that needs to be built separately]
  };
}

最后,将scripts/build.js中的大部分操作包装在一个循环中:

...
[various imports]
...

process.argv[2].split(' ').forEach(projectName => {
  const config = require('../config/webpack.config.prod')(projectName);
  const paths = require('../config/paths.prod')(projectName);
  ...
  [rest of build.js as normal]
}

之后,只需将服务器指向每个版本的正确文件,然后在要构建时运行yarn build "brand1 brand2"

接受这个答案,因为它现在正在为我工​​作,但是很想听听未来遇到它的任何人的潜在改进。