3

I have a problem with lazy loading and webpack.

There is a video of Sean Larkin showing how easy it is with webpack 4 to create a lazy loaded bundle (Here). But when I try to do it with typescript I run into some problems.

index.ts

export const someThing = something => import("./lazy/lazy");

and

lazy/lazy.ts
export default "I am lazy";

when I run it without any webpack configuration and name the files to ".js" I get a main chunk and a small chunk for the lazy loaded module.

But when I run it as ".ts" files with a simple webpack configuration I get just the "main.js" file and no extra chunk.

webpack.config.js
let config = {
    resolve: {
        extensions: [".ts", ".js"]
    },
    module: {
        rules: [
            { test: /\.ts$/, use: ["ts-loader"], exclude: /node_modules/ },
        ]
    },
}

module.exports = config;

and

tsconfig.json
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "noImplicitAny": false,
        "sourceMap": true,
        "lib": [ "es6", "dom" ],
        "removeComments": true
    }
}

Is there something to configure I am mission? What exactly is the difference between the import of a "js" file to a "ts" file?

3 Answers 3

14

Dynamic imports are an ES feature, you need to tell TypeScript to transform to ESNext to get import on the output, just change "module": "commonjs" to "module": "esnext".

Take this code :

export const LoadMe = () => import('./a-module')
  • "module": "commonjs" compiles to module.exports.LoadMe = () => require('a-module'), Webpack can't know if it's dynamic or just a normal require
  • "module": "esnext" compiles to export const LoadMe = () => import('a-module'), Webpack knows it's dynamic because it's a call expression to import
Sign up to request clarification or add additional context in comments.

3 Comments

thank you. That helps ;) Now I just have to make my code work with esnext ;)
How are you able to import plugins into your webpack.config.ts file, if you're using "module": "esnext"? I get a bunch of syntax errors whenever I try to import/require modules into my webpack file.
I don't use TypeScript for my Webpack config, but if you do you can use const module = require('somewhere') instead of import module from 'somewhere'. You might need @types/node to get require to work.
1

There is no way to configure the Typescript compiler to not touch certain imports. The old way of lazy loading works just as well though:

require.ensure([], require => {
  const lodash = require('lodash') as typeof import('lodash');
}, 'lodash-chunk');

this can be wrapped in a promise to achieve a very similar behavior to the ES6 import

function importLodash(): Promise<typeof import('lodash')> {
    return new Promise((resolve, reject) => {
        require.ensure([], require => {
            resolve(require('lodash'))
        }, reject, 'lodash-chunk');
    })
}

// then use it

const lodash = await importLodash();

*note- require.ensure is not generic - this function will need to be duplicated for every module you want to lazy load.

You'll also need to declare the require.ensure interface based on your enabled libs. I use this in my custom typings file

/* typings.d.ts */

declare global {
    const require: {
        // declare webpack's lazy loading interface
        ensure(deps: string[], cb: (lazyRequire: (path: string) => any) => void, chunkName: string): void;
        ensure(deps: string[], cb: (lazyRequire: (path: string) => any) => void, errCb: (err: Error) => void, chunkName: string): void;
    };
}

Comments

0

I have a trick one to lazyLoad a module with its type:

function lazyLoad(){ return let lazyModule:typeof import('xxx') = require('xxx'); }

limitation: the xxx can only be string not a variable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.