【问题标题】:Exclude JSON files from the main bundle with webpack for react-lottie使用 webpack 为 react-lottie 从主包中排除 JSON 文件
【发布时间】:2019-04-06 05:47:06
【问题描述】:

在我们的 Web 应用程序中,我们有一些 JSON 文件,每个文件大约 10-80k 行。这些都包含在我们的主包中。这些由名为 react-lottie 的动画插件使用。

我们webpack.config.js的一个例子

module.exports = {
  entry: ["./src/index.js"],
  module: {
    rules: [
      { test: /\.(js|jsx)$/, exclude: /node_modules/, use: ["babel-loader"] },
      {
        test: /\.(jpg|png|gif|ico)$/,
        use: {
          loader: "file-loader",
          options: { name: "[path][name].[hash].[ext]" }
        }
      }
    ]
  },
  resolve: { extensions: ["*", ".js", ".jsx"] },
  output: {
    path: __dirname + "/dist",
    publicPath: "/",
    filename: "[name].[hash].js"
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({ hash: false, template: "src/index.html" }),
    new DashboardPlugin(),
    new CopyWebpackPlugin([
      {
        from: "src/components/Assets/BookingBar.js",
        to: "assets/BookingBar.js"
      }
    ]),
    new BundleAnalyzerPlugin()
  ],
  devServer: {
    contentBase: "./dist",
    hot: true,
    historyApiFallback: true,
    port: 4000
  }
};

预期的行为是什么?

应该有一种方法可以从主包中排除 .json 文件。我试过 File-Loader、json-loader 和 const someJson = require(./someJson)

其他相关信息: 网络包版本:4.16.1 Node.js 版本:10.12.0

操作系统:Mac OS 10.14 Mojave

在下面回答(至少我是如何解决的)。如果没有任何数据,我无法初始化 lottie。

【问题讨论】:

  • 尝试阅读延迟加载,也称为代码拆分,因此最终 JSON 将作为一个块加载,而不是在主包中。
  • You can leverage Webpack's import 将 JSON 从您的主包中拆分出来。

标签: json reactjs webpack react-router


【解决方案1】:

最终,我在下面得到了答案,但在没有任何 JSON 数据的情况下无法初始化 lottie。我最终这样做了:

import React, { PureComponent } from "react"
import Lottie from 'react-lottie'

export default class AnimationAutomatedCommunication extends PureComponent {

  constructor(props) {
    super(props)
    this.state = {
      animation: <div />
    }
  }

  async componentDidMount() {
    const animation = await import(/* webpackChunkName: "AnimationAutomatedCommunication" */ './JsonData/AnimationAutomatedCommunication.json')
     const defaultOptions = {
       loop: true,
       autoplay: true,
       animationData: animation.default
     }
    this.setState({
      animation: <div className={this.props.className}>
        <Lottie key="lottie-win-jobs" options={defaultOptions}
                isStopped={this.props.isStopped} />
      </div>
    })
  }

  render() {
    return (
      <React.Fragment>
        {this.state.animation}
      </React.Fragment>
    )
  }
}

【讨论】:

    【解决方案2】:

    预期的行为是 JSON 将被捆绑,因为它可能在运行时同步需要。 JSON 数据不同于像图像文件这样由浏览器异步加载的数据,因为它们通过src 属性等呈现在页面上。

    正如 cmets 所提到的,您应该使用代码拆分。如果您安装并使用@babel/plugin-syntax-dynamic-import 插件,最新版本的Webpack 支持dynamic imports

    npm install --save-dev @babel/plugin-syntax-dynamic-import

    然后在babel.config.js:

    module.exports = {
      ...
      plugins: [
        "@babel/plugin-syntax-dynamic-import"
      ]
      ...
    };
    

    示例

    假设您有一个 React 组件,它可能需要一些 JSON 数据,但不需要将其作为捆绑包的一部分同步加载。您的 代码拆分版本可能如下所示:

    import React from 'react';
    import myJSON from './myJSON.json';
    
    export default class MyComponent extends React.Component {
      render() {
        return <div>{JSON.stringify(myJSON, null, 2)}</div>
      }
    }
    

    相反,您可以使用动态导入 - 基本上是运行时导入,它返回一个 Promise,您可以使用它来异步加载一些与您的包分开分块的数据:

    import React from 'react';
    import myJSON from './myJSON.json';
    
    export default class MyComponent extends React.Component {
      state = {data: {}};
      componentDidMount() {
        import(/* webpackChunkName: 'myJSON' */ './myJSON.json')
          .then((data) => {
            this.setState({data});
          });
      }
      render() {
        return <div>{JSON.stringify(this.state.data, null, 2)}</div>
      }
    }
    

    或者,您可以使用 React 的新 lazySuspense API(v16.6.0 及更高版本)到 dynamically import React components,它们与捆绑包分开分块。如果您想将组件及其对应的 JSON 数据分块在一起,但与主包分开,这可能会更可取:

    // MyComponent.jsx
    import React from 'react';
    import myJSON from './myJSON.json';
    
    export default class MyComponent extends React.Component {
      render() {
        return <div>{JSON.stringify(myJSON, null, 2)}</div>
      }
    }
    
    // SomeParent.jsx
    import React, {lazy, Suspense} from 'react';
    const MyComponent = lazy(() => import(/* webpackChunkName: 'MyComponent' */ './MyComponent'));
    
    export default class SomeParent extends React.Component {
      render() {
        return <div>
          <Suspense fallback={<div>Loading...<div>} >
            <MyComponent />
          </Suspense>
        </div>;
      }
    }
    

    在上面的示例中,&lt;MyComponent /&gt; 及其对应的代码(包括 JSON 数据)只会在组件在运行时实际呈现时才被加载。

    【讨论】:

    • 如果我不必用某种 JSON 数据初始化 react-lottie,那么您的答案将是完美的,不过我最终还是在代码库的其他地方使用了它,谢谢一个彻底的答复。
    • @GarrettJMU 您可以等待渲染 react-lottie 组件,直到 JSON 数据加载完毕。在我发布的第三个代码块中,您可以看到如何动态加载 JSON 数据并在数据可用时使用 Promise.then() 对其进行处理。
    猜你喜欢
    • 2017-07-10
    • 2018-12-22
    • 1970-01-01
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 2020-05-05
    • 1970-01-01
    相关资源
    最近更新 更多