【问题标题】:webpack imported module is not a constructorwebpack 导入的模块不是构造函数
【发布时间】:2018-10-30 07:23:18
【问题描述】:

我创建了一个小的 JS 模块,我打算制作一个 npm 包,但现在只是在 GitHub 上。这个模块是用 ES6 和 SCSS 编写的,因此依赖于 webpack 和 babel 进行编译。

为了测试它,我创建了一个具有类似设置(webpack 和 babel)的单独项目。在 npm 安装我的模块后,尝试将其导入我的 index.js 时,我在 Chrome 开发人员工具中收到以下错误:(x 是我的模块名称)

index.js:11 Uncaught TypeError: x__WEBPACK_IMPORTED_MODULE_1___default.a is not a constructor
    at eval (index.js:11)
    at Object../src/index.js (main.js:368)
    at __webpack_require__ (main.js:20)
    at eval (webpack:///multi_(:8081/webpack)-dev-server/client?:2:18)
    at Object.0 (main.js:390)
    at __webpack_require__ (main.js:20)
    at main.js:69
    at main.js:72

我查看了无数答案并尝试了无数解决方案,但无济于事。我的模块设置如下。

.babelrc

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["ie >= 11"]
      }
    }]
  ],
  "plugins": [
    "transform-es2015-modules-commonjs",
    "transform-class-properties"
  ]
}

webpack.common.js

const path = require('path')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const cleanWebpackPlugin = require('clean-webpack-plugin')

const baseSCSS = new ExtractTextPlugin('main/_base.css')
const themeSCSS = new ExtractTextPlugin('main/_theme.css')

module.exports = {
  entry: {
    example: [
      path.join(__dirname, 'src', 'example', 'index.js')
    ],
    main: [
      'idempotent-babel-polyfill',
      path.join(__dirname, 'src', 'index.js')
    ]
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: path.join('[name]', 'index.js')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        }
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          }
        )
      },
      {
        test: /\_base-scss$/,
        use: baseSCSS.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          }
        )
      },
      {
        test: /\_theme-scss$/,
        use: themeSCSS.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          }
        )
      }
    ]
  },
  plugins: [
    new cleanWebpackPlugin('dist', {}),
    new ExtractTextPlugin({ filename: path.join('example', 'style.css') }),
    baseSCSS,
    themeSCSS,
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: path.join(__dirname, 'src', 'example', 'index.html'),
      filename: path.join('example', 'index.html')
    })
  ]
}

webpack.prod.js

const merge = require('webpack-merge')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const webpack = require('webpack')
const common = require('./webpack.common.js')

module.exports = merge(common, {
  plugins: [
    new UglifyJSPlugin({
      sourceMap: true
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    })
  ],
  mode: 'production'
})

package.json

{
  "name": "my-module-name",
  "version": "1.0.0-beta.1",
  "description": "",
  "main": "dist/main/index.js",
  "scripts": {
    "start": "webpack-dev-server --config webpack.dev.js",
    "server": "node src/server",
    "format": "prettier-standard 'src/**/*.js'",
    "lint": "eslint src",
    "build": "webpack --config webpack.prod.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Liran",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-eslint": "^8.2.3",
    "babel-loader": "^7.1.4",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
    "babel-preset-env": "^1.7.0",
    "clean-webpack-plugin": "^0.1.19",
    "css-loader": "^0.28.11",
    "eslint": "^4.19.1",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "html-webpack-plugin": "^3.2.0",
    "idempotent-babel-polyfill": "^0.1.1",
    "node-sass": "^4.9.0",
    "prettier-standard": "^8.0.1",
    "sass-loader": "^7.0.1",
    "style-loader": "^0.21.0",
    "uglifyjs-webpack-plugin": "^1.2.5",
    "webpack": "^4.6.0",
    "webpack-cli": "^2.0.15",
    "webpack-dev-middleware": "^3.1.3",
    "webpack-dev-server": "^3.1.3",
    "webpack-merge": "^4.1.2"
  }
}

任何帮助/指针将不胜感激。如果您需要更多信息,请告诉我。

【问题讨论】:

  • 你的 libraryTarget 在你的 webpack 配置中设置的目标是什么?
  • 嗨@MatheusSilva,我的webpack 配置中没有这个属性。为了更加清晰,我已将整个设置添加到我的帖子中。
  • 哇@MatheusSilva,我不敢相信,但是在添加 library 和 libraryTarget 属性之后,我的模块现在可以在我的测试项目中完美运行!非常感谢您提供这个非常有用的指针。如果您想写一个简短的答案,其中包含需要添加的属性(库和 libraryTarget)和源(webpack 链接),我很乐意选择它作为接受的答案。

标签: javascript npm webpack babeljs es6-modules


【解决方案1】:

如果您不是库作者并且在使用另一个库时遇到问题,您可能会看到如下错误:

TypeError: [LIBRARY_NAME]__WEBPACK_IMPORTED_MODULE_3__ is not a constructor

如果是这种情况,您可能在代码中错误地导入了库(这可能是默认导出的问题)。仔细检查库文档的使用情况。

这可能就像改变这个一样简单:

import Foo from 'some-library/Foo';

到这里:

import { Foo } from 'some-library';

【讨论】:

  • 在 .js 文件中导入 Typescript 类时效果很好。
  • 您能否详细说明使用大括号和不使用大括号时的区别?谢谢!
  • @brance 当然。第一个不带花括号的示例称为“默认导出”,其中整个导出库可通过Foo 变量(例如Foo.doSomething())获得。带有花括号的第二个示例是“模块导出”模式,其中模块是从库中显式地从零碎中挑选出来的,这对于 treeshaking 来说是理想的。这个想法是,如果一个库有 100 个模块,而您只想使用 1 个,则此模式使其明确,因此模块捆绑器知道他们不需要引入其他 99 个模块,就像默认导出示例那样.
  • @DavidCalhoun 非常感谢您的解释!
【解决方案2】:

它不工作,因为它缺少libraryTarget and library 属性。通过执行该 webpack 知道您想要创建哪种格式的模块,即:commonjs (module.exports) 或 es (export)。

我会这样做:

...
  output: {
    path: path.join(__dirname, 'dist'),
    filename: path.join('[name]', 'index.js'),
    library: "my-library",
    libraryTarget: "umd" // exposes and know when to use module.exports or exports.
  },
...

【讨论】:

    【解决方案3】:

    除了设置libraryTarget之外,可能还需要将JavaScript文件中的export移动到默认值。

    function MyClassName() {
      ...
    }
    
    export default MyClassName;
    

    然后在 webpack 配置库类型 umd ...

    (请注意,我使用的是较新的library.type,而不是较旧的libraryTarget(请参阅https://webpack.js.org/configuration/output/#outputlibrarytarget)。

     const path = require('path');
     
     module.exports = {
        mode: "production",
        entry: '../wherever/MyClassName.js',
        
        output: {
            library: {
              name: "MyClassName",
              type: "umd",  // see https://webpack.js.org/configuration/output/#outputlibrarytype
              export: "default",  // see https://github.com/webpack/webpack/issues/8480
            },
            filename: 'MyClassName.min.js',
            path: path.resolve(__dirname, '../wherever/target/')
        },
        optimization: {
            minimize: true
        }
     };
    

    export default 使该类在 JavaScript 中可用,就像文件被直接嵌入一样,即,

    <script type="text/javascript" src="MyClassName.min.js"></script>
    <script type="text/javascript">
    <!--
    
    var myInstance = new MyClassName();
    
    // -->
    </script>
    

    免责声明:即使最初的问题到现在已经三年了,我还是添加了这个答案。遇到“不是构造函数”问题后,我花了几个小时搜索找到default 解决方案。这是第二次,我搜索并找到了它:D

    【讨论】:

      【解决方案4】:

      参照。 David Calhoun's answer,如果您使用第三方库遇到此问题,您可能会尝试将CommonJS module 导入为ECMAScript module。解决方法似乎是使用require 而不是import,例如,而不是

      import { Foo } from 'bar'
      

      你需要写

      const Foo = require('bar')
      

      (可能有更优雅的方式来处理这个问题,但这对我有用。)

      【讨论】:

        猜你喜欢
        • 2017-05-31
        • 2020-01-26
        • 2019-08-01
        • 2017-10-30
        • 2016-11-01
        • 2018-07-11
        • 1970-01-01
        • 2017-02-02
        • 1970-01-01
        相关资源
        最近更新 更多