在create-react-app中有条件地导入资产

时间:2019-03-06 11:55:52

标签: javascript reactjs webpack create-react-app es6-modules

使用create-react-app创建React应用时是否可以有条件地导入资产?我知道require语法-例如:

import React from "react";


const path = process.env.REACT_APP_TYPE === "app_1" ? "app_1" : "app_2";

const imagePath = require(`./assets/${path}/main.png`);

export default function Test() {
  return (
      <img src={imagePath} alt="" />
  );
}

但是,无论如何,这都会捆绑我的所有资产。

它将加载正确的映像,但仍将所有文件捆绑在一起,形成最终版本。

当我查看最终构建的开发工具时,即使我只想为app_1加载资产,也可以看到那里的所有资产。

我被迫触摸webpack配置,如果是的话,我应该改变什么?还是有其他方法?

4 个答案:

答案 0 :(得分:7)

在React不存在的日子里,我们没有将资产放入我们的JS文件中。我们让CSS决定为哪些选择器加载哪些资产。然后,您可以简单地为相应的元素(甚至整个页面)打开或关闭相应的类,然后中提琴会更改颜色,背景,甚至是形式。纯粹的魔法!

啊。这些是什么时间!

以上所有内容都是正确的,我不明白为什么有人会这样做或建议以其他方式建议这样做。但是,如果您仍然想要这样做(出于任何原因),则可以!最新的create-react-app通过动态导入和lazy loadingcode splitting任意组件提供了开箱即用的支持。您需要做的就是使用import()语句的括号版本而不是常规的语句。 import()照常接收请求字符串并返回Promise。而已。动态请求的组件的源代码不会被捆绑,而是存储在单独的块中以按需加载。

之前:

import OtherComponent from './OtherComponent';

function MyComponent() {   
  return (
    <div>
      <OtherComponent />
    </div>   
  ); 
}

之后:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  );
}

注意function MyComponent部分完全相同。

对于那些想知道它是否与CRA或React绑定的人而言,并非如此。 can be used in vanilla JavaScript是一个通用概念。

答案 1 :(得分:6)

需要使用webpack(或其他捆绑程序)。捆绑在一起时代码不会运行,因此编译器无法知道遵循哪个逻辑分支(app_1或app_2) )。因此,您必须了解捆绑程序的逻辑才能实现目标。

但是,这并没有看上去那么可怕,因为webpack内置了执行此操作的功能(不需要第三方...)

我会考虑使用webpack.providePlugin

https://webpack.js.org/plugins/provide-plugin

或其同级DefinePlugin

https://webpack.js.org/plugins/define-plugin

(恐怕这些例子已经浮现在我的头上了,因此它们不太可能在初次通过时起作用。)

示例:

两者都需要提供者模块...

// in path/provider.js

module.exports = {
  live: '/path/to/live/image',
  dev: '/path/to/dev/image'
}

提供插件示例

// in webpack

new webpack.ProvidePlugin({
    imagePath: [
      'path/provider',         // the file defined above
      process.env.ENVIRONMENT  // either 'dev' or 'live'
    ]
  }),
// in code

export default function Test() {
  return (
      <img src={imagePath} alt="" />
  );
}

定义插件示例:

// in webpack

new webpack.DefinePlugin({
  'process.env.ENVIRONMENT': JSON.stringify(process.env.ENVIRONMENT)
});
// in code

var providers = require('path/provider'); // same path provider as above

export default function Test() {
  return (
      <img src={providers[process.env.ENVIRONMENT]} alt="" />
  );
}

在两种情况下,捆绑器都必须在编译时(在发生捆绑之前)将变量折叠为实际文字值。由于您现在已经将逻辑路径折叠为一个选项,因此现在可以自由捆绑相关资产。

答案 2 :(得分:3)

您不能使用默认CRA设置来做到这一点。

因为如果您的动态需求动态导入路径不是静态,Webpack将无法确定要包含在其中的资产因此,最终的构建文件夹将从您的./src文件夹中抓取所有内容,并将其全部放入您的build文件夹中。

答案 3 :(得分:0)

有一种方法可以使用默认CRA设置

您可以在.env中添加类似内容

REACT_APP_SKIN=1

将您的皮肤资产放入public / css1,public / css2等中,并使用类似的代码将其包含在public / index.html中

<link href="/css%REACT_APP_SKIN%/theme.css" rel="stylesheet">