简体   繁体   English

使用webpack从主捆绑包中排除JSON文件以进行react-lottie

[英]Exclude JSON files from the main bundle with webpack for react-lottie

In our web app we have a few JSON files that are ~10-80k lines each. 在我们的网络应用中,我们有一些JSON文件,每个文件的行数约为10-80k。 These are getting included in our main bundle. 这些已包含在我们的主要捆绑包中。 These are used by an animation plugin called react-lottie. 这些由名为react-lottie的动画插件使用。

An example of our webpack.config.js 我们的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
  }
};

What is the expected behavior? 预期的行为是什么?

There should be a way to exclude .json files from the main bundle. 应该有一种从主捆绑包中排除.json文件的方法。 I've tried File-Loader, json-loader, and const someJson = require(./someJson) 我已经尝试了File-Loader,json-loader和const someJson = require(./ someJson)

Other relevant information: webpack version: 4.16.1 Node.js version: 10.12.0 其他相关信息:Webpack版本:4.16.1 Node.js版本:10.12.0

Operating System: Mac OS 10.14 Mojave 操作系统:Mac OS 10.14 Mojave

ANSWER BELOW (AT LEAST FOR HOW I SOLVED IT). 下面的答案(我如何解决)。 I couldn't initialize the lottie without any data. 没有任何数据,我无法初始化抽奖活动。

The expected behavior is that the JSON will get bundled because it's, presumably, needed synchronously at runtime. 预期的行为是JSON将被捆绑,因为大概在运行时需要同步。 JSON data differs from something like image files which are loaded asynchronously by the browser as they are rendered on the page via src attributes etc. JSON数据不同于图像文件之类的东西,它们是由浏览器异步加载的,因为它们是通过src属性等呈现在页面上的。

As the comments mentioned, you should be using code splitting. 如前所述,您应该使用代码拆分。 The latest version of Webpack supports dynamic imports if you install and use the @babel/plugin-syntax-dynamic-import plugin. 如果您安装并使用@babel/plugin-syntax-dynamic-import插件,则最新版本的Webpack支持动态 @babel/plugin-syntax-dynamic-import

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

Then in babel.config.js : 然后在babel.config.js

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

Example

Say you have a React component that might need some JSON data, but doesn't need to load it synchronously as part of the bundle. 假设您有一个React组件,它可能需要一些JSON数据,但不需要作为捆绑包的一部分同步加载。 Your non -code splitted version might look something like this: 您的代码拆分版本可能如下所示:

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

Instead you can use a dynamic import - basically a runtime import that returns a Promise you can use to asynchronously load some data chunked separately from your bundle: 相反,您可以使用动态导入-基本上是运行时导入,它返回一个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>
  }
}

Alternately, you can use React's new lazy and Suspense API (v16.6.0 and higher) to dynamically import React components that get chunked separately from the bundle. 另外,您可以使用React的新的lazySuspense API(v16.6.0及更高版本)来动态导入从捆绑包中分块出来的React组件 This might be preferable if you want to chunk a component and its corresponding JSON data together, but separately from the main bundle: 如果您想将组件及其对应的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>;
  }
}

In the above example, <MyComponent /> and its corresponding code -- including the JSON data -- will only be loaded when the component is actually rendered at runtime. 在上面的示例中, <MyComponent />及其相应的代码(包括JSON数据)仅在组件在运行时实际呈现时才加载。

Ultimately I took the answer above below me but wasn't able to initialize the lottie without any JSON data. 最终,我接受了上面的答案,但是没有任何JSON数据就无法初始化彩票。 I ended up doing this: 我最终这样做:

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>
    )
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM