question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow annotating dynamic import/require calls as non-critical (external)

See original GitHub issue

Do you want to request a feature or report a bug?

Request a feature.

What is the current behavior?

No matter what, if you have an import or a require call that takes in a variable (instead of a string literal), Webpack will warn that the request of a dependency is an expression.

If the current behavior is a bug, please provide the steps to reproduce.

const myImport = async (bundleName) => {
    try {
        return {
            // Critical dependency: the request of a dependency is an expression
            contents: await import(bundleName),
            succeeded: true,
        }
    } catch (error) {
        return {
            error,
            succeeded: false,
        }
    }
};

What is the expected behavior?

Although the complaint is good & valid most of the time, there are cases in which we do want dynamic imports.

  • On a SPA with many components, we could be eagerly pre-fetching bundles in the background based on a list of bundle names to load. Other places in code could also start loading these modules.
  • When unit testing, it’s cleaner to use dependency injection (passing in a function) to stub out external calls than to still use import/require and rely on test framework overrides such as Jest manual mocks.

If this is a feature request, what is motivation or use case for changing the behavior?

I’m trying to build classes to keep track of which requests are in-progress/succeeded/failed. Because we don’t have a hook to stop Webpack from complaining, we have to pass the import into load, which seems like extra work that’s easy to mismatch & cause a difficult-to-find bug with:

F.A.Q.s

Don’t do this. Webpack needs to be able to statically analyze what you are referring to.

+1 to the static analysis. But, we only ever use this to load external bundles, never for stuff in the same bundle. We want the static analysis to assume the bundle is external.

Are these “external bundles” actually bundled code you have already locally, or something you can install as a node module and not depend on an arbitrary non webpack’dd bundle?

They’re different folders of app code (different Webpack entry points). The goal is to lazy load them. They’re still under our src/ (which hasn’t moved to a monorepo)

If the source is available at build time, why not import() that module path?

There are many sources and we want to make this code generic & testable. See bullets under expected behavior.

Why not create a function unifiedFailHandlers(err) { /* error handling */ } and .catch in the already-async import calls?

This isn’t just error handling. Even if it were, that seems like an unnecessary level of indirection when the ideal solution would be to tell webpack “don’t worry, assume this is external”.

This situation sounds improbable and over-engineered. Code sample?

Oversimplifying it (TypeScript annotations just to make the code clearer), here’s what we want the class skeleton to look like:

type INativeImport<TContents> = (bundleName: string) => Promise<TContents>;

class BundleImporter {
    private readonly nativeImport: INativeImport;
    
    public constructor(nativeImport: INativeImport) {
        this.nativeImport = nativeImport;
    }

    public async load(bundleName: string) {
        try {
            return {
                // Critical dependency: the request of a dependency is an expression
                contents: await import(bundleName),
                succeeded: true,
            }
        } catch (error) {
            return {
                error,
                succeeded: false,
            }
        }
    }
}

/* webpackDisableComplaintAboutDynamicImportPrettyPlease */
const nativeImport: INativeImport = (bundleName: string) => await import(bundleName);

const bundleImporter = new BundleImporter(nativeImport);

bundleImporter.load("delayed");

Here’s what we ended up having to do:

type INativeImport<TContents> = (bundleName: string) => Promise<TContents>;

class BundleImporter {
    public async load(bundleName: string, nativeImport: INativeImport) {
        try {
            return {
                // Critical dependency: the request of a dependency is an expression
                contents: await import(bundleName),
                succeeded: true,
            }
        } catch (error) {
            return {
                error,
                succeeded: false,
            }
        }
    }
}

const bundleImporter = new BundleImporter(nativeImport);

bundleImporter.load("delayed", async () => import("delayed")); // eww

Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.

Node: >=9.5 Webpack: 3 (soon to be 4) Browser support matrix: modern browsers + IE 11 OS: Mac & Windows

Sorry for such a long OP, everyone I’ve asked about this tends to have a whole bunch of questions varying on the FAQs. 😂

/cc @TheLarkInn since we talked about this briefly offline, and @ian-craig so he’ll sign off on my pull request sooner

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:2
  • Comments:16 (12 by maintainers)

github_iconTop GitHub Comments

3reactions
sokracommented, Feb 15, 2018

DRYing up is possible. Just make sure to keep string and import() together.

// instead of
function load(str) { return import(str).then(...).catch(...); }
load("something");
load("anywhere");
// prefer this
function load(factory) { return factory().then(...).catch(...); }
load(() => import("something"));
load(() => import("anywhere"));
2reactions
shawnmcleancommented, Aug 12, 2021

I got webpack to not intercept the import but now it’s converting the import to require.

import(/* webpackIgnore: true */ url);

to

require(/* webpackIgnore: true */ url);

Any ideas what settings I need here?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Advanced Features: Dynamic Import - Next.js
Dynamically import JavaScript modules and React Components and split your code into manageable chunks.
Read more >
Dynamic Imports with JavaScript : Adam Bien's Weblog
Dynamic Imports with JavaScript. With the function-like dynamic import() statement: const lazy = async _ => { const module = await import(".
Read more >
Linter rules - Dart
Avoid annotating with dynamic when not required. This rule is available as of Dart 2.0.0. This rule has a quick fix available.
Read more >
5. The IoC container - Spring
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC)principle. IoC is also known as dependency injection (DI).
Read more >
TSConfig Reference - Docs on every TSConfig option
In some cases where no type annotations are present, TypeScript will fall back ... Without this flag, using an export from a UMD...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found