【问题标题】:Typescript w Webpack import legacy javascript class_1.class is not a constructorTypescript w Webpack import legacy javascript class_1.class 不是构造函数
【发布时间】:2017-10-12 01:35:17
【问题描述】:

我有一个项目,我正在从 Javascript 迁移到 Typescript。有很多 Legacy Javascript 以前没有设置为导出/导入,而是连接在一起。我正在尝试将旧 Javascript 类导入 Typescript 代码,但在尝试创建导入的 javascript 类的新实例时遇到错误。

我正在使用 Webpack 构建最终的 app.js 文件。 Babel 正在 Webpack 中运行。

目录结构:

webpack.config.js
tsconfig.json
.babelrc
legacy-js/
--LegacyJSClass.js
new-ts/
--NewTSClass.ts
ts-build/
--legacy-js/
----LegacyJSClass.js
----LegacyJSClass.js.map
--new-ts/
----NewTSClass.js
----NewTSClass.js.map
dist/
--webpack-output-file.js

./legacy-js/LegacyJSClass.js:

class LegacyJSClass {
    constructor(data) {
        data = data || {};
        this.ExampleJsProp = data.ExampleProp;
    }
}

export { LegacyJSClass };

./new-ts/NewTSClass.ts

import { LegacyJSClass } from "../legacy-js/LegacyJSClass";

export class NewTSClass {
    ExampleTsProp: any = new LegacyJSClass();
    constructor() {
        console.log(this.ExampleTsProp);
    }
}

let tsClass = new NewTSClass();

./tsconfig.json

{
  "compilerOptions": {
    "outDir": "./ts-build",
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es5",
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "traceResolution": true
  },
  "compileOnSave": true,
  "include": [
    "./new-ts/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

./webpack.config.js

var webpack = require('webpack');
var ManifestPlugin = require('webpack-manifest-plugin');

module.exports = {
    name: 'app',
    devtool: 'inline-source-map',
    plugins: [
        new ManifestPlugin()
    ],
    module: {
        preLoaders: [
            {
                test: /\.js%/,
                loader: 'eslint',
                exclude: /node_modules/
            },
            {
                test: /\.js$/,
                loader: 'source-map-loader',
                exclude: /node_modules/
            }
        ],
        loaders: [
            {
                test: /\.ts?$/,
                loader: 'awesome-typescript-loader',
                exclude: /node_modules/
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader",
                options: {
                    presets: ['env']
                }
            }
        ]
    },
    resolve: {
        extensions: [".ts", ".js"]
    },
    entry: __dirname + '/new-ts/NewTSClass',
    output: {
        filename: 'webpack-output-file.js',
        path: __dirname + '/dist'
    },
    eslint: {
        failOnWarning: false,
        failOnError: true
    },
    externals: {
        "jquery": "jquery"
    }
};

./.babelrc

{
  "presets": [ "env" ],
  "plugins": [
    "transform-remove-export" // This removes the export statements from the LegacyJS since it is still contatenated together and output as one big file and doesn't use a module loader.
  ]
}

一切都正确编译,但是当我尝试在浏览器中加载 webpack-output-file.js 时,它给了我错误:

NewTSClass.ts:20 Uncaught TypeError: LegacyJSClass_1.LegacyJSClass is not a constructor
    at new NewTSClass (NewTSClass.ts:20)
    at Object.<anonymous> (NewTSClass.ts:26)
    at __webpack_require__ (bootstrap 4a128ff…:19)
    at Object.defineProperty.value (bootstrap 4a128ff…:39)
    at bootstrap 4a128ff…:39

经过进一步调查,Typescript 似乎正确地移动了所有内容:

./ts-build/legacy-js/LegacyJSClass.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var LegacyJSClass = (function () {
    function LegacyJSClass(data) {
        data = data || {};
        this.ExampleJsProp = data.ExampleProp;
    }
    return LegacyJSClass;
}());
exports.LegacyJSClass = LegacyJSClass;
//# sourceMappingURL=LegacyJSClass.js.map

./ts-build/new-ts/NewTSClass.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var LegacyJSClass_1 = require("../legacy-js/LegacyJSClass");
var NewTSClass = (function () {
    function NewTSClass() {
        this.ExampleTsProp = new LegacyJSClass_1.LegacyJSClass();
        console.log(this.ExampleTsProp);
    }
    return NewTSClass;
}());
exports.NewTSClass = NewTSClass;
var tsClass = new NewTSClass();
//# sourceMappingURL=NewTSClass.js.map

但是,当这些通过 Webpack/babel 运行时......它们的转换方式不同:

./dist/webpack-output-file.js

/******/

// Webpack 引导的东西...

/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var LegacyJSClass_1 = __webpack_require__(1);
    var NewTSClass = (function () {
        function NewTSClass() {
            this.ExampleTsProp = new LegacyJSClass_1.LegacyJSClass();
            console.log(this.ExampleTsProp);
        }
        return NewTSClass;
    }());
    exports.NewTSClass = NewTSClass;
    var tsClass = new NewTSClass();

/***/ }),
/* 1 */
/***/ (function(module, exports) {
    "use strict";

    var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

    function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

    var LegacyJSClass = function LegacyJSClass(data) {
        _classCallCheck(this, LegacyJSClass);

        data = data || {};
        this.ExampleJsProp = data.ExampleProp;

    };

/***/ })
/******/ ]);
// Sourcemap info...

我已经尝试了所有我能找到的不同方法,但无法让它发挥作用。如果我将 js 模块导出更改为export default LegacyJSClass,则会出现错误LegacyJSClass_1.default is not a constructor

我希望它工作的最终原因是因为我不想为每个使用的遗留类创建定义的类型文件,并且有太多需要立即移植到 typescript 的文件。应用程序的其余部分仍然使用旧版 js,因此它必须在新的 Typescript 正在开发和缓慢发布的同时继续工作。

【问题讨论】:

    标签: javascript typescript webpack ecmascript-6 babeljs


    【解决方案1】:

    您正在使用babel-plugin-transform-remove-export,它会从 JavaScript 文件中删除所有导出,并且您的 .babelrc 中的注释在使用 webpack 时不正确(它可能是旧构建系统的遗留物)。 Webpack 使用实际的导出,只是 webpack 提供了导出对象以使其在浏览器中工作。您尝试使用的导入在 babel 处理的模块中不存在,正如您在 webpack 输出中看到的那样,模块 1 中没有导出。如果您尝试在 TypeScript 中注销 LegacyJSClass文件,你会看到它是 undefinedundefined 不是构造函数(坦率地说,错误消息不是很丰富)。

    您必须从 .babelrc 中删除插件,并且您也不需要在 babel-loader 上的 webpack 配置中再次配置预设,因为它将使用 .babelrc

    {
      "presets": [ "env" ]
    }
    

    【讨论】:

    • 这行得通。我不知道如果 webpack babel 配置已经在 webpack 配置中定义,它会访问我的 babelrc。 babelrc 被一个连接所有旧 JS 的旧 gulp 进程使用。包含导出删除是因为该遗留 JS 没有模块加载器。我将 babel 设置直接放在 gulp-babel 插件声明中,并从我的 babelrc 中删除了 transform-remove-export 插件,一切正常。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-25
    • 2020-03-02
    • 2023-01-04
    相关资源
    最近更新 更多