How to force TypeScript to not compile to JS when I have an error, with Webpack Encore setup

Viewed 3901

I'm using Webpack Encore in my project to compile TypeScript to JavaScript. The setup is working perfectly, but I would like my watch/build command to break, when I have an error in my TypeScript code. Now I know that in a TS project I would have to set "noEmitOnError": true in my tsconfig.json's compilerOptions object.

Right now my webpack.config.js looks like this.

const Encore = require('@symfony/webpack-encore');
const babelLoader = {
    test: /\.js$/,
    loader: 'babel-loader',
    query: {
        presets: [
            [
                "@babel/preset-env",
                {
                    "useBuiltIns": "entry",
                    "corejs": {version: 3, proposals: true}
                },
            ]
        ]
    }
};

Encore
    .setOutputPath('public/build/')
    .copyFiles({
        from: './assets/images',
        to: 'images/[path][name].[hash:8].[ext]'
    })
    .setPublicPath('/build')
    .cleanupOutputBeforeBuild()
    .enableVersioning()
    .enableSourceMaps()
    .addEntry('app', './assets/ts/app.ts')
    .addEntry('admin', './assets/ts/admin/app.ts')
    .enableTypeScriptLoader()
    .enableForkedTypeScriptTypesChecking()
    .addLoader(babelLoader)
    .enablePostCssLoader()
    .enableSassLoader((options) => {
        options.outputStyle = 'compressed';
    })
    .enableSingleRuntimeChunk()
    .splitEntryChunks();

const config = Encore.getWebpackConfig();

// needed for Vagrant VM for watch mode to work correctly
config.watchOptions = {
    poll: true
};

module.exports = config;

The lines responsible for TS compilation are

.enableTypeScriptLoader()
.enableForkedTypeScriptTypesChecking()

According to WebPack Encore's docs the enableForkedTypeScriptTypesChecking method should make Encore use my tsconfig.json.

My tsconfig.json looks like this:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "sourceMap": true,
    "noEmitOnError": true
  },
  "files": [
    "core.ts",
    "sys.ts",
    "types.ts",
    "scanner.ts",
    "parser.ts",
    "utilities.ts",
    "binder.ts",
    "checker.ts",
    "emitter.ts",
    "program.ts",
    "commandLineParser.ts",
    "tsc.ts",
    "diagnosticInformationMap.generated.ts"
  ]
}

So I have "noEmitOnError": true in my compiler options. But then when I make a deliberate error in my TS code (eg.: remove an argument from a function call) - which also gets correctly highlighted in my IDE as an error - then I run either encore dev or encore prodcution then my build passes and I see the compiled, bundled JS files in my build directory.

Also I have the compilation target set to ES6, but when I look into my compiled bundles, I see that all my let and const variable declarations got transpiled to ES5 compatible var statements.

So it seems that TS compiler is ignoring what I tell it in tsconfig.json. In my folder structure I have tsconfig.json, webpack.config.js and package.json all next to each other in the root directory.

Also when I console.log the result of Encore.getWebpackConfig() in my webpack.config.js I see that compilerOptions is an empty object. So the question is essentially; why doesn't the TypeScript compiler get my config?

1 Answers

Since you're using TS with webpack, you need to tell webpack itself to stop on errors, not just TS:

https://webpack.js.org/configuration/optimization/#optimizationnoemitonerrors

Adding config.optimization.noEmitOnErrors = true; before exporting your config should do the trick, I don't think there's a specific setting for this through Encore.

There should also be no need for .enableForkedTypeScriptTypesChecking() if it's just for picking up tsconfig.json - this should also be done by .enableTypeScriptLoader(), which allows a custom configuration as well.

Based on your addEntry calls, your files TS config is likely incorrect and not needed btw.

Related