Why does ts-loader not compile my typescript?
Asked Answered
G

2

7

I am trying to use Webpack to compile some typescript using ts-loader but it is not running tsc as I'm expecting. If I make changes to a ts file, webpack is not compiling it back to js, the same happens if I delete the generated js file altogether and re-run webpack.

Typescript is set up fine because I can run ./node_modules/typescript/bin/tsc and it generates the js files just fine. Am I right in thinking that ts-loader is just supposed to run tsc against my tsconfig.json? If so, why does it not pick up changes and generate my js as expected?

As you can see, my entry point is ./Client/boot-client.ts and not even this gets compiled when running through webpack.

The specific webpack command I'm running is:

./node_modules/webpack/bin/webpack.js --progress

Which gives the following output

[0] building modulests-loader: Using [email protected] and C:\git\coliver\couchtrace\Couchtrace.Web\tsconfig.json
[1] building modulests-loader: Using [email protected] and C:\git\coliver\couchtrace\Couchtrace.Web\tsconfig.json
[1] Hash: 568887199c9c2bcbe47ec00669704990969dbee5
Version: webpack 2.3.2
Child
    Hash: 568887199c9c2bcbe47e
    Time: 20096ms
                 Asset    Size  Chunks                    Chunk Names
        main-client.js  554 kB       0  [emitted]  [big]  main-client
    main-client.js.map  859 kB       0  [emitted]         main-client
       [0] delegated ./node_modules/rxjs/Observable.js from dll-reference vendor_c9f874e7c2f104739cd8 42 bytes {0} [not cacheable] [built]
       [5] delegated ./node_modules/rxjs/Subject.js from dll-reference vendor_c9f874e7c2f104739cd8 42 bytes {0} [not cacheable] [built]
      [14] delegated ./node_modules/@angular/core/index.js from dll-reference vendor_c9f874e7c2f104739cd8 42 bytes {0} [not cacheable] [built]
      [19] ./~/rxjs/AsyncSubject.js 1.6 kB {0} [built]
      [20] ./~/rxjs/ReplaySubject.js 2.99 kB {0} [built]
      [33] delegated ./node_modules/angular2-universal/browser/index.js from dll-reference vendor_c9f874e7c2f104739cd8 42 bytes {0} [not cacheable] [built]
      [34] ./~/rxjs/add/operator/map.js 156 bytes {0} [built]
      [60] ./Client/src/app.module.ts 1.86 kB {0} [built]
      [61] delegated ./node_modules/angular2-universal-polyfills/browser.js from dll-reference vendor_c9f874e7c2f104739cd8 42 bytes {0} [not cacheable] [built]
      [68] ./~/rxjs/Rx.js 9.61 kB {0} [built]
     [180] ./~/rxjs/add/operator/takeUntil.js 186 bytes {0} [built]
     [335] ./Client/boot-client.ts 951 bytes {0} [built]
     [344] delegated ./node_modules/rxjs/symbol/rxSubscriber.js from dll-reference vendor_c9f874e7c2f104739cd8 42 bytes {0} [not cacheable] [built]
     [351] delegated ./node_modules/rxjs/util/ObjectUnsubscribedError.js from dll-reference vendor_c9f874e7c2f104739cd8 42 bytes {0} [not cacheable] [built]
     [353] delegated ./node_modules/@angular/router/index.js from dll-reference vendor_c9f874e7c2f104739cd8 42 bytes {0} [not cacheable] [built]
        + 345 hidden modules
Child
    Hash: c00669704990969dbee5
    Time: 20085ms
             Asset    Size  Chunks                    Chunk Names
    main-server.js  552 kB       0  [emitted]  [big]  main-server
       [5] delegated ./node_modules/rxjs/Subject.js from dll-reference ./vendor 42 bytes {0} [not cacheable] [built]
      [14] delegated ./node_modules/@angular/core/bundles/core.umd.js from dll-reference ./vendor 42 bytes {0} [not cacheable] [built]
      [19] ./~/rxjs/AsyncSubject.js 1.6 kB {0} [built]
      [20] ./~/rxjs/ReplaySubject.js 2.99 kB {0} [built]
      [21] ./~/rxjs/util/ArgumentOutOfRangeError.js 974 bytes {0} [built]
      [32] delegated ./node_modules/angular2-universal/node/index.js from dll-reference ./vendor 42 bytes {0} [not cacheable] [built]
      [53] delegated ./node_modules/rxjs/add/operator/map.js from dll-reference ./vendor 42 bytes {0} [not cacheable] [built]
      [59] ./Client/src/app.module.ts 1.86 kB {0} [built]
      [60] delegated ./node_modules/zone.js/dist/zone-node.js from dll-reference ./vendor 42 bytes {0} [not cacheable] [built]
      [61] delegated ./node_modules/angular2-universal-polyfills/node.js from dll-reference ./vendor 42 bytes {0} [not cacheable] [built]
      [62] delegated ./node_modules/aspnet-prerendering/index.js from dll-reference ./vendor 42 bytes {0} [not cacheable] [built]
      [69] ./~/rxjs/Rx.js 9.61 kB {0} [built]
     [336] ./Client/boot-server.ts 1.37 kB {0} [built]
     [356] delegated ./node_modules/rxjs/symbol/rxSubscriber.js from dll-reference ./vendor 42 bytes {0} [not cacheable] [built]
     [360] delegated ./node_modules/@angular/router/bundles/router.umd.js from dll-reference ./vendor 42 bytes {0} [not cacheable] [built]
        + 346 hidden modules

Versions

  • webpack: 2.3.2
  • ts-loader: 2.0.3
  • typescript: 2.2.2

webpack.config.js

var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path');
var webpack = require('webpack');
var merge = require('webpack-merge');

// Configuration in common to both client-side and server-side bundles
var sharedConfig = {
    context: __dirname,
    resolve: { extensions: [ '.ts', '.js' ]  },
    output: {
        filename: '[name].js',
       // publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
    },
    module: {
        rules: [
            { test: /\.js$/, enforce: 'pre', use: 'source-map-loader' },
            { test: /\.ts$/, enforce: 'pre', use: 'source-map-loader' },
            { test: /\.ts$/, use: ['ts-loader', 'angular2-template-loader'], exclude: /node_modules/ },
            { test: /\.html$/, use: 'html-loader?minimize=false' },
            { test: /\.css$/, use: ['to-string-loader','css-loader'] },
            { test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'url-loader', query: { limit: 25000 } },
            { test: /\.json$/, use: 'json-loader' }
        ]
    }
};

// Configuration for client-side bundle suitable for running in browsers
var clientBundleOutputDir = './wwwroot/dist';
var clientBundleConfig = merge(sharedConfig, {
    entry: { 'main-client': './Client/boot-client.ts' },
    output: { path: path.join(__dirname, clientBundleOutputDir) },
    plugins: [
        new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require('./wwwroot/dist/vendor-manifest.json')
        })
    ].concat(isDevBuild ? [
        // Plugins that apply in development builds only
        new webpack.SourceMapDevToolPlugin({
            filename: '[file].map', // Remove this line if you prefer inline source maps
            moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
        })
    ] : [
        // Plugins that apply in production builds only
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin()
    ]),
    target: 'web',
    devtool: 'inline-source-map'
});

// Configuration for server-side (prerendering) bundle suitable for running in Node
var serverBundleConfig = merge(sharedConfig, {
    resolve: { mainFields: ['main'] },
    entry: { 'main-server': './Client/boot-server.ts' },
    plugins: [
        new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require('./Client/dist/vendor-manifest.json'),
            sourceType: 'commonjs2',
            name: './vendor'
        })
    ],
    output: {
        libraryTarget: 'commonjs',
        path: path.join(__dirname, './Client/dist')
    },
    target: 'node'
});

module.exports = [clientBundleConfig, serverBundleConfig];

tsconfig.json

{
  "compilerOptions": {
    "noImplicitAny": false,
    "moduleResolution": "node",
    "target": "es5",
    "sourceMap": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipDefaultLibCheck": true,
    "lib": [ "es6", "dom" ],
    "types": [ "node" ]
  },
  "exclude": [ "bin", "node_modules" ]
}
Gastelum answered 28/3, 2017 at 22:45 Comment(0)
J
6

ts-loader does not write any file to disk. It compiles your TypeScript files and passes the resulting JavaScript to webpack, this happens in memory. There is no reason to output the compiled JavaScript as it's included in the bundle. The bundle contains everything you need.

You can see that the ./Client/boot-client.ts is compiled (it does not mean written to disk) by the following line:

[335] ./Client/boot-client.ts 951 bytes {0} [built]
Jair answered 28/3, 2017 at 23:19 Comment(2)
Ahh, ok well that makes sense. So is it recommended to skip the manual typescript compile in favor of just having webpack do its thing via ts-loader? I should only have ts files in my src and shouldn't have a need for the corresponding js files there too?Gastelum
Yes, if you're using webpack, you don't need to worry about having JS files. Whether you want to use webpack or compile them manually, depends if you want to bundle the app or not (basically the same reason for using webpack with JS).Jair
T
0

After spending an hour or two on the same problem, OP's question under Michael Jungo's answer lead to an elegant solution, so +1, Michael.

To illustrate with a minimal example, given the following Webpack configuration:

let config = {
    entry: {
        'index': path.join(__dirname, 'index.ts')
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.(ts|tsx)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: require.resolve('ts-loader')
                    }
                ]
            }
        ]
    }
};

The solution is to instead allow Webpack's default TypeScript compilation behaviour:

let config = {
    entry: {
        'index': path.join(__dirname, 'index.ts')
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
};
Thusly answered 5/5 at 7:40 Comment(1)
Webpack itself does not run any TS compilation out of the box. It is actually what ts-loader for. You may also use babel-loader to strip out all TS types instantly and make type-checking before or in parallel with a standard compiler tsc with a flag --noEmit.Jeroldjeroma

© 2022 - 2024 — McMap. All rights reserved.