9

I had ended up doing some refactoring around routes to allow for code splitting but following the react/webpack instructions I've still got just the 2 entry bundles being generated.

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/**/*", ], } 

I expected a new chunk to be generated for the EconomyManager lazy import but the build only generates a main.[hash].js and semantic.[hash].js. Where am I going wrong here?

I checked and EconomyManager exports are not being referenced anywhere else in the application as I thought that might be it.

3 Answers 3

8

@babel/preset-env might be transpiling your dynamic imports to deferred requires, this will prevent Webpack from knowing where to code split.

We will need to exclude the plugin @babel/plugin-proposal-dynamic-import so your import() statements are preserved. Try adding the exclude field to your @babel/preset-env options in your Webpack config.

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

This is described in similar GitHub Issues:

Sign up to request clarification or add additional context in comments.

Comments

0

If you set the 'moduleResolution' property to 'NodeNext' in tsconfig, it creates.

 "compilerOptions": { "moduleResolution": "NodeNext", "module": "commonjs", } 

Comments

0

I ran into this problem, and after making tsconfig.json changes described in other answers and at https://github.com/webpack/webpack/issues/5703, I still wasn't getting separate chunks. For me the problem was that I was using SplitChunksPlugin to separate out common chunks, which was getting the dynamically imported modules. The solution to having both dynamically imported chunks and common chunks is to use the chunks: 'initial' option for common chunks:

https://webpack.js.org/plugins/split-chunks-plugin/#splitchunkschunks

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.