Exported TypeScript Class not included in WebPack bundle if not used directly

泄露秘密 提交于 2019-12-12 02:54:26

问题


I'm converting a javascript project with Angular 1.x to WebPack and TypeScript (using ts-loader). I got it mostly working, but I'm running into trouble when ts-loader seems to be optimizing my scripts out of the bundle when the exports are not directly used.

Here's a sample project demonstrating the issue (npm install, webpack, then load index.html and watch the console).

https://github.com/bbottema/webpack-typescript

The logging from ClassA is showing up, but angular is reporting ClassB missing (provider). If you look in bundle.js you'll notice ClassB missing entirely. The difference is ClassA begin use directly after importing, and ClassB is only referenced by type for compilation.

Is it a bug, or is there a way to force ClassB to be included? Or am I going about it wrong? Angular 2 would probably solve this issue, but that's a step too large right now.

Relevant scripts from the project above:


package.json

{
    "devDependencies": {
        "typescript": "^1.7.5",
        "ts-loader": "^0.8.1"
    },
    "dependencies": {
        "angular": "1.4.9"
    }
}

webpack.config.js

var path = require('path');

module.exports = {
    entry: {
        app: './src/entry.ts'
    },
    output: {
        filename: './dist/bundle.js'
    },
    resolve: {
        root: [
            path.resolve('./src/my_modules'),
            path.resolve('node_modules')
        ],
        extensions: ['', '.ts', '.js']
    },
    module: {
        loaders: [{
            test: /\.tsx?$/,
            loader: 'ts-loader'
        }]
    }
};

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs"
  },
  "exclude": [
    "node_modules"
  ]
}

index.html

<!doctype html>
<html ng-app="myApp">
    <body>
        <script src="dist/bundle.js"></script>
    </body>
</html>

entry.js

declare var require: any;

'use strict';

import ClassA = require('ClassA');
import ClassB = require('ClassB');

var a:ClassA = new ClassA(); // direct use, this works

var angular = require('angular');

angular.module('myApp', []).
    // this compiles as it should, but in runtime the provider will not be packaged and angular will throw an error
    run(function(myProvider: ClassB) {
    }
);

ClassA.ts

// this line will be logged just fine
console.log('ClassA.ts: if you see this, then ClassA.ts was packaged properly');

class ClassA {
}

export = ClassA;

ClassB.ts

declare var require: any;

// this line is never logged
console.log('ClassB.ts: if you see this, then ClassB.ts was packaged properly');

class ClassB {
}

var angular = require(angular);

angular.module('myApp').service(new ClassB());

export = ClassB;

回答1:


Turns out you have to signal WebPack to explicitly include a module by adding an extra require call without import statement.

I'm not ready to mangle my .ts files by adding duplicate imports, so I made a generic solution for that using the preprocessor loader:

{
    "line": false,
    "file": true,
    "callbacks": {
    "fileName": "all",
    "scope": "line",
    "callback": "(function fixTs(line, fileName, lineNumber) { return line.replace(/^(import.*(require\\(.*?\\)))/g, '$2;$1'); })"
    }]
}

As a proof of concept, this regex version is very limited it only support the following format:

import ClassA = require('ClassA');
// becomes
require('ClassA');import ClassA = require('ClassA');

But it works for me. Similarly, I'm adding the require shim:

{
    "fileName": "all",
    "scope": "source",
    "callback": "(function fixTs(source, fileName) { return 'declare var require: any;' + source; })"
}

I made a sample project with this solution.



来源:https://stackoverflow.com/questions/35504680/exported-typescript-class-not-included-in-webpack-bundle-if-not-used-directly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!