Webpack 动态导入 .json 文件?

Posted

技术标签:

【中文标题】Webpack 动态导入 .json 文件?【英文标题】:Webpack dynamic import .json file? 【发布时间】:2020-01-19 22:14:48 【问题描述】:

我将 React Intl 用于 x 种语言(如下示例),目前我在设置我的应用程序时导入以下内容:

import  addLocaleData  from 'react-intl';
import locale_en from 'react-intl/locale-data/en';
import locale_de from 'react-intl/locale-data/de';

import messages_en from './translations/en.json';
import messages_de from './translations/de.json';

addLocaleData([...locale_en, ...locale_de]);

...
export const messages = 
    en: messages_en,
    de: messages_de

由于无论使用哪种语言都会导入这些语言文件,因此我的主捆绑 js 文件变得非常大,尤其是来自 .json 文件。

如何使用 Webpack 拆分这些语言文件(或使用 CopyWebpackPlugin 将它们复制到我的 dist 文件夹),然后根据当前使用的语言动态导入它们?

该应用程序是同构的,因此相同的代码正在服务器上运行。

【问题讨论】:

【参考方案1】:

我最近一直在做类似的事情,尽管我的项目不需要 s-s-r。我发现将动态导入语法与 React 的 Suspense 组件配对可以达到预期的效果。这是我发现的工作的粗略概述,至少在我的情况下,不包括 s-s-r:

// wrap this around your JSX in App.js:
<React.Suspense fallback=<SomeLoadingComponent />>
  <AsyncIntlProvider>
    /* app child components go here */
  </AsyncIntlProvider>
</React.Suspense>

// the rest is in support of this
// can be placed in another file
// simply import AsyncIntlProvider in App.js

const messagesCache = ;

const AsyncIntlProvider = ( children ) => 
  // replace with your app's locale getting logic
  // if based on a hook like useState, should kick off re-render and load new message bundle when locale changes (but I haven't tested this yet)
  const locale = getLocale();

  const messages = getMessages(locale);
  return (
    <IntlProvider locale=locale messages=messages>
      children
    </IntlProvider>
  );
;

function getMessages(locale) 
  if (messagesCache[locale]) 
    return messagesCache[locale];
  
  // Suspense is based on ErrorBoundary
  // throwing a promise will cause <SomeLoadingComponent /> to render until the promise resolves
  throw loadMessages(locale);


async function loadMessages(locale) 
  // dynamic import syntax tells webpack to split this module into its own chunk
  const messages = await import('./path/to/$locale.json`);
  messagesCache[locale] = messages;
  return messages;

Webpack 应该将每个语言环境 JSON 文件拆分为自己的块。如果没有,则可能在动态导入语法到达 webpack 之前将其转换为不同的模块系统(require 等)。例如:如果使用 Typescript,tsconfig 需要 "module": "esnext" 来保留 import() 语法。如果使用 Babel,它也可能会尝试进行模块转译。

单个语言环境的块输出将如下所示;肯定比通过 CopyWebpackPlugin 实现的要多:

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],

/***/ "./path/to/en-US.json":
/*!*************************************!*\
  !*** ./path/to/en-US.json ***!
  \*************************************/
/*! exports provided: message.id, default */
/***/ (function(module) 

eval("module.exports = JSON.parse(\"\\\"message.id\\\":\\\"Localized message text\\\"\");//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvbG9jYWxpemF0aW9uL2VuLVVTLmpzb24uanMiLCJzb3VyY2VzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./path/to/en-US.json\n");

/***/ )

]);

希望这是一个很好的起点,可以与 s-s-r 一起使用,也可以修改为与 s-s-r 一起使用。请报告您在该主题上的发现。 ?

【讨论】:

以上是关于Webpack 动态导入 .json 文件?的主要内容,如果未能解决你的问题,请参考以下文章

typescript 动态导入与 tsconfig.json 中的 webpack.config 冲突?

使用 Webpack 文件加载器导入静态 json 文件给出文件路径而不是 json 内容

如何从 Web 服务动态导入 SVG 并内联渲染

如何在 Webpack 中生成动态导入块名称

使用 Webpack 动态导入命名导出

使用 Webpack 4.5 + Babel 6 + React 16 导入 JSON 时出错