最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - 'Cannot find module' when using dynamic import - Stack Overflow

programmeradmin5浏览0评论

I've deleted CRA and configured webpack/babel on my own. Now I have problems with dynamic imports.

This works fine:

import("./" + "CloudIcon" + ".svg")
  .then(file => {
  console.log(file);
})

This doesn't work:

const name = 'CloudIcon';

import("./" + name + ".svg")
  .then(file => {
  console.log(file);
})

I've tried to export files with different types. It didn't work. Have tried to use Webpack Magic Comments, but didn't help either.

I suppose, that something is wrong with my webpack/babel settings, but what?

babel.config.js:

const plugins = [
  "@babel/syntax-dynamic-import",
  ["@babel/plugin-transform-runtime"],
  "@babel/transform-async-to-generator",
  "@babel/plugin-proposal-class-properties"
];


if (process.env.NODE_ENV === 'development') {
  plugins.push('react-refresh/babel'); 
}

module.exports = {
  presets: [[
    "@babel/preset-env", {
      "debug": false,
      "modules": false,
      "useBuiltIns": false
    }],
    ['@babel/preset-react', {throwIfNamespace: false}],
    '@babel/preset-typescript'
  ],
  plugins,
};

webpack.config.js:

require('dotenv').config();
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const webpack = require('webpack');

const reactAppVars = (() => {
  const obj = {};
  for (let key in process.env) {
    if (key.startsWith('REACT_APP_')) obj[key] = process.env[key];
  }
  return obj;
})();

const target = process.env['NODE_ENV'] === 'production' ? 'browserslist' : 'web';

const plugins = [
  new webpack.EnvironmentPlugin({'NODE_ENV': process.env['NODE_ENV'], 'PUBLIC_URL': '', ...reactAppVars}),
  new HtmlWebpackPlugin({template: path.resolve(__dirname, '../public/index.html')}),
  new MiniCssExtractPlugin({filename: '[name].[contenthash].css'}),
  new webpack.ProvidePlugin({process: 'process/browser'}),
  new webpack.ProvidePlugin({"React": "react"}),
];

if (process.env['SERVE']) plugins.push(new ReactRefreshWebpackPlugin());

const proxy = {
//Proxy settings
}

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "../build"),
    assetModuleFilename: '[path][name].[ext]'
  },
  plugins,
  devtool: 'source-map',
  devServer: {
    static: {
      directory: path.resolve(__dirname, "../public"),
    },
    proxy,
    port: 9999,
    hot: true,
  },

  module: {
    rules: [
      { test: /\.(html)$/, use: ['html-loader'] },
      {
        test: /\.(s[ac]|c)ss$/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'sass-loader'
        ]
      },
      {
        test: /\.less$/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          {
            loader: 'less-loader',
            options: {
              lessOptions: {
                javascriptEnabled: true
              }
            }
          }
        ]
      },
      {
        test: /\.(png|jpe?g|gif|webp|ico)$/i,
        type: process.env['NODE_ENV'] === 'production' ? 'asset' : 'asset/resource'
      },
      {
        test: /\.svg$/i,
        issuer: /\.[jt]sx?$/,
        use: ['@svgr/webpack', {
          loader: 'file-loader',
          options: {
            name: '[path][name].[ext]'
          }
        }],
      },
      {
        test: /\.(woff2?|eot|ttf|otf)$/i,
        type: process.env['NODE_ENV'] === 'production' ? 'asset' : 'asset/resource'
      },
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
          }
        }
      },
      {
        test: /\.([cm]?ts|tsx)$/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [
              "@babel/preset-env",
              "@babel/preset-react",
              "@babel/preset-typescript",
            ]
          }
        }
      },
      {
        test: /\.md$/,
        loader: "raw-loader"
      },
    ],
  },
  resolve: {
    'roots': [path.resolve('./src')],
    'extensions': ['', '.js', '.jsx', '.ts', '.tsx'],
    extensionAlias: {
      ".js": [".js", ".ts"],
      ".cjs": [".cjs", ".cts"],
      ".mjs": [".mjs", ".mts"]
    },
    fallback: {
      'process/browser': require.resolve('process/browser')
    }
  },
  mode: process.env['NODE_ENV'],
  target
}

I've deleted CRA and configured webpack/babel on my own. Now I have problems with dynamic imports.

This works fine:

import("./" + "CloudIcon" + ".svg")
  .then(file => {
  console.log(file);
})

This doesn't work:

const name = 'CloudIcon';

import("./" + name + ".svg")
  .then(file => {
  console.log(file);
})

I've tried to export files with different types. It didn't work. Have tried to use Webpack Magic Comments, but didn't help either.

I suppose, that something is wrong with my webpack/babel settings, but what?

babel.config.js:

const plugins = [
  "@babel/syntax-dynamic-import",
  ["@babel/plugin-transform-runtime"],
  "@babel/transform-async-to-generator",
  "@babel/plugin-proposal-class-properties"
];


if (process.env.NODE_ENV === 'development') {
  plugins.push('react-refresh/babel'); 
}

module.exports = {
  presets: [[
    "@babel/preset-env", {
      "debug": false,
      "modules": false,
      "useBuiltIns": false
    }],
    ['@babel/preset-react', {throwIfNamespace: false}],
    '@babel/preset-typescript'
  ],
  plugins,
};

webpack.config.js:

require('dotenv').config();
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const webpack = require('webpack');

const reactAppVars = (() => {
  const obj = {};
  for (let key in process.env) {
    if (key.startsWith('REACT_APP_')) obj[key] = process.env[key];
  }
  return obj;
})();

const target = process.env['NODE_ENV'] === 'production' ? 'browserslist' : 'web';

const plugins = [
  new webpack.EnvironmentPlugin({'NODE_ENV': process.env['NODE_ENV'], 'PUBLIC_URL': '', ...reactAppVars}),
  new HtmlWebpackPlugin({template: path.resolve(__dirname, '../public/index.html')}),
  new MiniCssExtractPlugin({filename: '[name].[contenthash].css'}),
  new webpack.ProvidePlugin({process: 'process/browser'}),
  new webpack.ProvidePlugin({"React": "react"}),
];

if (process.env['SERVE']) plugins.push(new ReactRefreshWebpackPlugin());

const proxy = {
//Proxy settings
}

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "../build"),
    assetModuleFilename: '[path][name].[ext]'
  },
  plugins,
  devtool: 'source-map',
  devServer: {
    static: {
      directory: path.resolve(__dirname, "../public"),
    },
    proxy,
    port: 9999,
    hot: true,
  },

  module: {
    rules: [
      { test: /\.(html)$/, use: ['html-loader'] },
      {
        test: /\.(s[ac]|c)ss$/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'sass-loader'
        ]
      },
      {
        test: /\.less$/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          {
            loader: 'less-loader',
            options: {
              lessOptions: {
                javascriptEnabled: true
              }
            }
          }
        ]
      },
      {
        test: /\.(png|jpe?g|gif|webp|ico)$/i,
        type: process.env['NODE_ENV'] === 'production' ? 'asset' : 'asset/resource'
      },
      {
        test: /\.svg$/i,
        issuer: /\.[jt]sx?$/,
        use: ['@svgr/webpack', {
          loader: 'file-loader',
          options: {
            name: '[path][name].[ext]'
          }
        }],
      },
      {
        test: /\.(woff2?|eot|ttf|otf)$/i,
        type: process.env['NODE_ENV'] === 'production' ? 'asset' : 'asset/resource'
      },
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
          }
        }
      },
      {
        test: /\.([cm]?ts|tsx)$/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [
              "@babel/preset-env",
              "@babel/preset-react",
              "@babel/preset-typescript",
            ]
          }
        }
      },
      {
        test: /\.md$/,
        loader: "raw-loader"
      },
    ],
  },
  resolve: {
    'roots': [path.resolve('./src')],
    'extensions': ['', '.js', '.jsx', '.ts', '.tsx'],
    extensionAlias: {
      ".js": [".js", ".ts"],
      ".cjs": [".cjs", ".cts"],
      ".mjs": [".mjs", ".mts"]
    },
    fallback: {
      'process/browser': require.resolve('process/browser')
    }
  },
  mode: process.env['NODE_ENV'],
  target
}
Share Improve this question asked Nov 10, 2022 at 11:35 SentenzoSentenzo 391 silver badge6 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 4

What is basically happen that when you have defined import path, webpack will include that code in already existing chunk. When you have a dynamic import (which translated to Regex) it will take all files that correspond to this Regex and place them in a different chunk.

It hard to determine from the details if you serve this additional chunks and the browser can reach them. Network and server logs is a good start.

https://webpack.js/guides/code-splitting/#prefetchingpreloading-modules

The problem was the extensions array in webpack

'extensions': ['', '.js', '.jsx', '.ts', '.tsx']

I changed it to this

'extensions': ['.js', '.jsx', '.ts', '.tsx', '...']

And now everything works fine.

import



Dynamic expressions in import()

  • https://webpack.js/api/module-methods/#dynamic-expressions-in-import
  • It is not possible to use a fully dynamic import statement, such as import(foo). Because foo could potentially be any path to any file in your system or project.
# Will not work
await import(path)

# Will work
await import('./anyHardcoded/path.js')
await import(/* webpackIgnore: true */ path);
  • The import() must contain at least some information about where the module is located. Bundling can be limited to a specific directory or set of files so that when you are using a dynamic expression - 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 puted, any file like english.json or german.json will be available for consumption.



Magic Comments

// Single target
import(
  /* webpackChunkName: "my-chunk-name" */
  /* webpackMode: "lazy" */
  /* webpackExports: ["default", "named"] */
  /* webpackFetchPriority: "high" */
  'module'
);

// Multiple possible targets
import(
  /* webpackInclude: /\.json$/ */
  /* webpackExclude: /\.noimport\.json$/ */
  /* webpackChunkName: "my-chunk-name" */
  /* webpackMode: "lazy" */
  /* webpackPrefetch: true */
  /* webpackPreload: true */
  `./locale/${language}`
);



webpackIgnore

- import(/* webpackIgnore: true */ path);
发布评论

评论列表(0)

  1. 暂无评论