Search code examples
typescriptwebpackts-loader

Wepack force typescript files to be included using ts-loader


I've gotten into TypeScript and played around with Browserify (with tsify), it worked fine until I switched to Webpack to use vue and babel with my project.

Here is my project structure (simplified, it's also using ASP.NET Core) :

BestAppEver
  ---| [C# stuff]
  ---| scripts
       ---| pages
               - Login.ts
               - Dashboard.ts
       ---| components
               - CoolThing.vue
       - App.ts
  - package.json
  - webpack.config.js
  - tsconfig.json

The files in pages usually contain jquery declarations like these:

import * as $ from "jquery";
console.log("hi i got loaded!");
$("#deleteConfirmationInput").change(function() {
    if (isInputValid()) {
        $("#deleteConfirmationButton").removeAttr("disabled");
    } else {
        $("#deleteConfirmationButton").attr("disabled", "disabled");
    }
});

And this is my webpack.config.js file

var path = require('path');
var webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
    entry: './scripts/App.ts',
    mode: process.env.NODE_ENV || 'production',
    output: {
        path: path.resolve(__dirname, 'wwwroot/js'),
        filename: 'bundle.js',
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader',
            },
            {
                test: /\.ts(x?)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader'
                    },
                    {
                        loader: 'ts-loader',
                        options: {
                            appendTsSuffixTo: [/\.vue$/]
                        }
                    }
                ]
            }
        ]
    },
    resolve: {
        extensions: ['.ts', '.tsx', '.js', '.vue', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        },
        plugins: [
            new TsconfigPathsPlugin()
        ]
    }
    plugins: [
        new VueLoaderPlugin()
    ],
    devtool: 'source-map'
}

if (process.env.NODE_ENV === 'production') {
    // http://vue-loader.vuejs.org/en/workflow/production.html
    module.exports.plugins = (module.exports.plugins || []).concat([
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: '"production"'
            }
        }),
        new webpack.LoaderOptionsPlugin({
            minimize: true
        })
    ]);
}

With Browserify and tsify, all the files were included and ran, so "hi i got loaded!" was printed out.

With ts-loader, only the files that i imported and used are included and ran. Without importing the file, "hi i got loaded!" was not printed out. This wasn't the case with .vue files.

Is there a way to automatically import those files and make them all run in the final bundle?

Thanks :D


Solution

  • The simple answer is exactly what you discovered: you must import the files! Webpack only traverses the file tree starting from the file you name as the entry (./scripts/App.ts). Anything else is simply never seen by webpack.

    Note that you can use "bare imports" to import the file only for the side effect:

    import "./pages/Login.ts";
    

    In this case, you are telling webpack that you don't expect Login.ts to export anything, but the file should be included in the bundle. You can place these bare imports in your App.ts.

    This question may be relevant: ES6 Bare Import: How to use, and when?


    Another option is configuring webpack to use multiple values for entry. In your case, you should be able to define entry as an array of strings:

    entry: [
      './scripts/App.ts',
      './scripts/Pages/Login.ts',
      './scripts/Pages/Component.ts'
    ],
    

    If you want to be clever, you can dynamically generate this by recursively listing files in the scripts directory. webpack.config.js is just javascript (node) after all. If interested, I can expand the answer to include an example of this.