webpack: Dynamic expressions for import() are broken

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

What is the current behavior? Per this doc I expect the following code to work, but it throws an error: https://webpack.js.org/guides/migrating/#dynamic-expressions

const withIndex = (base) => `${base}/index`
import(withIndex('./somePath'))
// Uncaught (in promise) Error: Cannot find module './somePath/index'.

And yet, adding an empty string resolves the problem:

const withIndex = (base) => `${base}/index`
import('' + withIndex('./somePath')) // concat an empty string, tada

This makes no sense.

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

  1. import() a file using a string path to prove you can
  2. save string path to variable and try to import using variable, doesn’t work
  3. try again by passing '' + variable into import() to see the bug

MVP Repo: https://github.com/joefraley/lazy-loading-rr4-example/tree/MVP-broken-imports

git clone https://github.com/joefraley/lazy-loading-rr4-example/tree/MVP-broken-imports && cd lazy-loading-rr4-example && npm i && npm start

You can see the MVP working by opening your browser console while running the example. You can play with goofy errors by opening source/parent-dir/child-dir/index.js and commenting/uncommenting different import statements listed there.

What is the expected behavior? import() should ideally accept real variables, but should definitely be consistent between its treatment of import(var) and import('' + var)

If this is a feature request, what is motivation or use case for changing the behavior? want to use centrally defined functions like const getComponent = (path) => import(path) when lazy loading react components

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

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 14
  • Comments: 16 (4 by maintainers)

Most upvoted comments

@matowang webpack

Webpack will collects all the dependencies, then check the import statement, parse the params to a reg statement, like this:

import('./app'+path+'/util') => /^\.\/app.*\/util$/

Webpack look for modules that meet the criteria based on reg. So if the param is a variable, Webpack will use the wrong reg statement to look for modules, in other words, will look for modules globally.

You can examine the reg in Dev Tools.

There also seem to be problems resolving index in some cases and not others.

import('./child-dir') // knows that i want child-dir/index.js
import('../../child-dir') // doesn't know how to find index.js
import('../../child-dir/index.js') // works fine

@navono I meant that something like this works

const path = "assets/image1.png";
import("../" + path);

but this doesn’t work

const path = "../assets/image1.png";
import(path);

I thought this was what you meant. Does the outside file reference need to be written in the import statement? My app only works when I use import(“…/” + path);

import() can resolve certain kinds of dynamic expressions.

Your import() example is, from the point of view of the import() analyzer, just import(randomFunctionCall(randomArguments)). webpack doesn’t know that the function you are calling is pure and does nothing but return a string.

Also, import('' + anything) will work by bundling literally everything webpack can find, as it has no idea if anything starts with a . or .. or whatever else.

Also it might be outside the scope of this issue to explain the API to me, but I don’t understand at all how this works. The error message suggests that webpack evaluates the function call to a valid string, pointing to the correct module path.

// Uncaught (in promise) Error: Cannot find module './somePath/index

So at best the error is very misleading

@Kovensky are the abilities/limitations of that import API documented? How does one know what it understands and what it doesn’t? For example, how do you know this:

Also, import(‘’ + anything) will work by bundling literally everything webpack can find, as it has no idea if anything starts with a . or … or whatever else

I’m having a similar problem using create-react-app version 16.4.1

Trying to create an AsyncRoute component to make it easier for code splitting and came across an issue where a variable string passed to import reports an error of Unhandled Rejection (Error): Cannot find module './../Site/Site.js'., though the same path resolves correctly as a normal static import.

Heres example code:

const AsyncComponent = (imp, namedExport='default')=>{
    return class AsyncComp extends React.Component{
        state = {}

        componentDidMount(){
            imp().then(comp=>{
                this.setState({component:comp})
            })
        }

        render(){
            return (this.state.component && this.state.component[namedExport]) || null;
        }
    }
}
class AsyncRoute extends React.Component{
    render(){
        return <Route path={this.props.path} exact={this.props.exact} component={AsyncComponent(()=>import(''+this.props.componentPath))}/>
    } 
}

Is this a bug or expected behaviour?

@outofthisworld you must specify the relative path in import. For example the file layout: dynamicimport2

I have demo repo to represent this. I hope this helps.

@navono thanks for solving my problem! I was just randomly browsing and saw your comment. Why does the relative path have to be in strings?

@outofthisworld you must specify the relative path in import. For example the file layout: dynamicimport2

I have demo repo to represent this. I hope this helps.