为啥 webpack 没有从我的动态导入中生成块?

Posted

技术标签:

【中文标题】为啥 webpack 没有从我的动态导入中生成块?【英文标题】:Why is webpack not generating chunks from my dynamic imports?为什么 webpack 没有从我的动态导入中生成块? 【发布时间】:2020-03-25 10:51:42 【问题描述】:

我最终围绕路由进行了一些重构以允许代码拆分,但按照 react/webpack 说明,我仍然只生成了 2 个入口包。

Index.tsx

import React from "react"
import  render  from "react-dom"
import  Provider  from "react-redux"
import  store  from "services/configureStore"
import  ConnectedApp  from "src/App"
import  ConnectedFeatureToggleProvider  from "./components/AppWrapper/FeatureToggleProvider"

const renderApp = () => 
  render(
    <Provider store=store>
      <ConnectedFeatureToggleProvider>
        <ConnectedApp />
      </ConnectedFeatureToggleProvider>
    </Provider>,
    document.querySelector("#app"),
  )


// run app when FIT Core functions are ready
window.onFitCoreReady = () => 
  renderApp()


App.tsx

import React,  useEffect, Suspense  from "react"
import  hot  from "react-hot-loader/root"
import  connect  from "react-redux"
import  Switch, Redirect, Route, Router  from "react-router-dom"
// import  ConnectedEconomyManager  from "modules/economyManager/EconomyManager"
import  ConnectedPlayerAccounts  from "modules/playerAccountDataManager/PlayerAccounts"
import  HealthDashboard  from "modules/healthDashboard/HealthDashboard"
import  PackSimulator  from "modules/packSimulator/PackSimulator"

const mapStateToProps = (state: GlobalState) => (
  ...
)

const mapDispatchToProps = (dispatch: Dispatch) => (
  ...
)

type Props = 


const ConnectedEconomyManager = React.lazy(() => import("modules/economyManager/EconomyManager"))

export const App = (
: Props) => 
  return (
      <Router history=history>
          <Suspense fallback=<span>LOADING LOADING LOADING</span>>
            <Switch>
              <Redirect
                exact
                from="/marketplace/"
                to=
                  pathname: "/marketplace/economy",
                  search: window.location.search,
                
              />
              <Route path="/marketplace/economy" component=ConnectedEconomyManager />
              <Route path="/marketplace/playerAccounts" component=ConnectedPlayerAccounts />
              <Route path="/marketplace/health" component=HealthDashboard />
              <Route path="/marketplace/packSimulator" component=PackSimulator />
            </Switch>
          </Suspense>
      </Router>
  )


export const ConnectedApp = hot(connect(mapStateToProps, mapDispatchToProps)(App))

webpack/local.js

const webpack = require('webpack');
const htmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const _ = require('lodash');
const common = require('./common');
const path = require('path');

const open = process.env.npm_package_config_WEBPACK_OPEN_WINDOW === 'true';
const host = process.env.npm_package_config_WEBPACK_LOCAL_HOST;
const port = process.env.npm_package_config_WEBPACK_PORT;
const ROOT_DIR = path.resolve(__dirname, '../');
const APP_DIR = path.resolve(ROOT_DIR, 'src');

module.exports = env => 
  if (!env) 
    // Prevent references to 'undefined'
    env = ;
  
  return merge.smart(common, 
    mode: 'development',
    devServer: 
      disableHostCheck: true,
      port: '443',
      historyApiFallback: true,
      open: open ? 'Google Chrome' : open, // auto-open in browser
      openPage: 'marketplace/economy?project=' + projectName,
    ,
    devtool: 'eval-source-map',
    module: 
      rules: [
        _.merge(
          _.find(common.module.rules, rule => rule.use && rule.use.loader === 'babel-loader'),
           use:  options:  plugins: ['@babel/plugin-syntax-dynamic-import', 'babel-plugin-styled-components', '@babel/plugin-proposal-class-properties']   
        ),
        
          test: /\.css$/,
          use: ['style-loader', 'css-loader'],
        ,
         test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] ,
         test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] ,
      ],
    ,
    plugins: [
      // copies the index.html file to the build directory:
      new HtmlWebpackPlugin( 
        template: `$APP_DIR/index.html`,
        templateParameters: 
          ...define
        
      ),
    ],
  );

webpack/common.js

const path = require('path');
const webpack = require('webpack');

const ROOT_DIR = path.resolve(__dirname, '../');
const BUILD_DIR = path.resolve(ROOT_DIR, 'dist');
const APP_DIR = path.resolve(ROOT_DIR, 'src');

module.exports = 
  entry: 
    main: [
      `$APP_DIR/index.tsx`, // main entry point to the application
    ],
    semantic: path.resolve(ROOT_DIR, 'semantic-theme', 'semantic.less'),
  ,
  module: 
    rules: [
      
        test: /\.[j|t]sx?$/,
        use: 
          loader: 'babel-loader',
          options: 
            presets: [['@babel/preset-env',  useBuiltIns: 'entry', corejs: '3.0.0' ], '@babel/preset-react'],
            overrides: [
              
                test: /\.tsx?$/,
                presets: [['@babel/preset-env',  useBuiltIns: 'entry', corejs: '3.0.0' ], '@babel/preset-react', '@babel/preset-typescript'],
              ,
            ],
          ,
        ,
        include: APP_DIR,
      ,names
      
        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: 'url-loader?limit=10000&mimetype=application/font-woff',
      ,
      
        test: /\.(ttf|otf|eot|svg|png|jpe?g|gif)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: 'file-loader',
      ,
    ],
  ,
  output: 
    path: `$BUILD_DIR`,
    filename: '[name].[hash].js',
    chunkFilename: '[name].[hash].js',
    publicPath: '/',
  ,
  resolve: 
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
    modules: [
      ROOT_DIR,
      APP_DIR,
      'node_modules',
    ],
    alias: 
      // tell semantic-ui-less to use our theme config
      '../../theme.config$': path.resolve(ROOT_DIR, 'semantic-theme', 'theme.config'),
      'react-dom': '@hot-loader/react-dom',
    ,
  ,
  stats:  colors: true ,
;

tsconfig.json


  "compilerOptions": 
      "plugins": [
        
          "name": "typescript-styled-plugin"
        
      ],
      "noEmit": true,
      "strict": true,
      "sourceMap": true,
      "noImplicitAny": false,
      "noUnusedLocals": true,
      "module": "esnext",
      "target": "esnext",
      "lib": [
        "esnext",
        "dom"
      ],
      "moduleResolution": "node",
      "jsx": "preserve",
      "allowSyntheticDefaultImports": true,
      "resolveJsonModule": true,
      "baseUrl": ".",
      "paths": 
        "components/*": ["src/components/*"],
        "modules/*": ["src/modules/*"],
        "services/*": ["src/services/*"],
      ,
      "types": [
        "react",
        "jest",
      ]
  ,
  "include": [
    "./src/**/*",
    "./@types/**/*",
  ],


我希望为 EconomyManager 惰性导入生成一个新块,但构建只生成一个 main.[hash].jssemantic.[hash].js。我哪里错了?

我检查并发现EconomyManager 导出没有在应用程序的其他任何地方被引用,因为我认为可能是这样。

【问题讨论】:

【参考方案1】:

@babel/preset-env 可能会将您的动态导入转换为延迟需求,这将阻止 Webpack 知道在哪里进行代码拆分。

我们需要排除插件@babel/plugin-proposal-dynamic-import,以便保留您的import() 语句。尝试将排除字段添加到 Webpack 配置中的 @babel/preset-env 选项中。

presets: [['@babel/preset-env',  useBuiltIns: 'entry', corejs: '3.0.0', exclude: ['proposal-dynamic-import'] ]

这在类似的 GitHub 问题中有所描述:

https://github.com/babel/babel/issues/11204 https://github.com/babel/babel/issues/10194

【讨论】:

以上是关于为啥 webpack 没有从我的动态导入中生成块?的主要内容,如果未能解决你的问题,请参考以下文章

Webpack 从我的样式表中的内联 SVG 中去除标签,我不知道为啥

为啥 tailwindcss 没有在 webpack 中使用 sass 文件正确导入所有组件?

vue + webpack:动态组件导入是如何工作的?

为啥我在一个 webpack 项目上得到“意外的令牌导入”,而在另一个项目上却没有?

为啥 webpack 不能导入 PrimeReact CSS 文件?

无法使用 webpack 导入 icomoon 自定义字体