Using webpack 3 and react, I can import a file like this:
import(`src/Main.sass`).then(...do something)
I have a loader for the imported files that changes the module content based on a query string, and I can successfully import a file like this:
import(`src/Main.sass?theme=themename`).then(...do something)
But when the query string is a variable:
const themeQuery = '?theme=themename';
import(`src/Main.sass${themeQuery}`).then(...do something);
or
const theme = 'themename';
import(`src/Main.sass?theme=${theme}`).then(...do something);
I get the error:
Error: Cannot find module '.src/Main.sass?theme=themename'.
I would expect this to work based on the information here:
Fully dynamic statements, such as import(foo), will fail because webpack requires at least some file location information. This is because foo could potentially be any path to any file in your system or project. The import() must contain at least some information about where the module is located, so bundling can be limited to a specific directory or set of files.
and
Every module that could potentially be requested on an import() call is included. For example, import(
./locale/${language}.json
) will cause every .json file in the ./locale directory to be bundled into the new chunk. At run time, when the variable language has been computed, any file like english.json or german.json will be available for consumption.
This is not a fully dynamic statement and it has the full file path (location information) that can be imported with no problem sans query string.
Edit: I've created a test repo where this can be reproduced. src/Main.js
imports Mainponent.sass
with a query string defined by a prop, themeName
. When using this component as <Main/>
in src/App.js
, you can see the Cannot find module './Main.module.sass?theme=themename' error.
However, when importing using the full string, including the query, the file is imported with no issue. This can be seen by using src/Main-no-var.js
as the <Main>
component.
Here is the webpack config used for this example.
Using webpack 3 and react, I can import a file like this:
import(`src/Main.sass`).then(...do something)
I have a loader for the imported files that changes the module content based on a query string, and I can successfully import a file like this:
import(`src/Main.sass?theme=themename`).then(...do something)
But when the query string is a variable:
const themeQuery = '?theme=themename';
import(`src/Main.sass${themeQuery}`).then(...do something);
or
const theme = 'themename';
import(`src/Main.sass?theme=${theme}`).then(...do something);
I get the error:
Error: Cannot find module '.src/Main.sass?theme=themename'.
I would expect this to work based on the information here:
Fully dynamic statements, such as import(foo), will fail because webpack requires at least some file location information. This is because foo could potentially be any path to any file in your system or project. The import() must contain at least some information about where the module is located, so bundling can be limited to a specific directory or set of files.
and
Every module that could potentially be requested on an import() call is included. For example, import(
./locale/${language}.json
) will cause every .json file in the ./locale directory to be bundled into the new chunk. At run time, when the variable language has been computed, any file like english.json or german.json will be available for consumption.
This is not a fully dynamic statement and it has the full file path (location information) that can be imported with no problem sans query string.
Edit: I've created a test repo where this can be reproduced. src/Main.js
imports Main.component.sass
with a query string defined by a prop, themeName
. When using this component as <Main/>
in src/App.js
, you can see the Cannot find module './Main.module.sass?theme=themename' error.
However, when importing using the full string, including the query, the file is imported with no issue. This can be seen by using src/Main-no-var.js
as the <Main>
component.
Here is the webpack config used for this example.
Share Improve this question edited Mar 6, 2018 at 18:21 CLL asked Mar 5, 2018 at 23:17 CLLCLL 1,3423 gold badges13 silver badges27 bronze badges 3 |2 Answers
Reset to default 7If you look at this part of documentation
For example, import(./locale/${language}.json) will cause every .json file in the ./locale directory to be bundled into the new chunk. At run time, when the variable language has been computed, any file like english.json or german.json will be available for consumption.
This means that static analysis will search for every .json
file within ./locale/
folder and bundle it, meaning it'll know every possible target. With query string
you'll have basically infinite number of possible targets because query string
could be anything and therefore won't be able to know what to bundle.
I guess this is just entirely different functionality from dynamic path
resolution which obviously is not supported in the current import()
statement.
Your best bet is to change folder structure to have multiple .css
files for each theme and then load it using dynamic path
as suggested in documentation (language example) or you could do something like this
const themes = {
"themename": () => import(
`./Main.module.css?theme=themename`
),
// other themes
}
This way you'd have cleaner code showing all possible themes that can be passed to prop
(static analysis would know exactly what the query string
is, so it will work) and then you'd use it like so
componentDidMount = () => {
const { themeName } = this.props
themes[themeName]().then((result) => {
this.setState({ theme: result })
})
}
I'd rather have the query string implementation as you've suggested but for now, as far as I've investigated, it's not possible.
I've just discovered this article, and it states that Webpack has "loading strategies".
At first I thought the comment in the example below was innocuous, but no, it's precisely what sets Webpack's loading strategy.
import(/* webpackMode: "eager" */ `assets/images/${imageName}.jpg`)
There are four different methods (lazy, lazy-once, eager, weak). You can take a look into the descriptions in more detail here.
All credits to the author of the article.
Use case
I needed to import a localized version of FirebaseUI in Quasar (a great Vue.js framework), so instead of using import
, which fails with dynamic strings, forcing me to hardcode the language desired:
import * as firebaseui from 'firebaseui/dist/npm__it'
I now use:
import (/* webpackMode: "eager" */ `firebaseui/dist/npm__${appLanguage}`)
It allows me to evaluate the languate before the import statement, either by the detecting it in the browser, or by parsing the URL for the language query term.
webpack.congfig.js
and.babelrc
– Aaqib Commented Mar 5, 2018 at 23:42webpack.config
used. There is no.babelrc
for this example. – CLL Commented Mar 6, 2018 at 18:22