awesome-typescript-loader does not pick up changes in JSON
Asked Answered
T

1

8

Assume I have some JSON file (let's name it template.json)

{
    "myField1": "",
    "myField2": ""
}

I also have a kind of generic class

export default GenericClass<T> {
    // Creating an empty constuctor with passed type.
    // to allow define type automatically.
    // This allow us not to manually set generic type for class
    // and also allows Webpack to pick up changes.
    constructor(template?: T) {} 

    // ...some fields and methods

    get typedField(): T {
        return /* something slightly calculated */
    }
}

I'm using it like a type in my Typescript project:

import GenericClass from "path/to/GenericClass"
import template from "template.json"

export type TemplateType = typeof template
export default new GenericClass(template)

// we can also write
//     export default new GenericClass<TemplateType>()
// but in this case the changes in template.json
// won't be picked up by Webpack.
// However, this does not affects the problem,
// it occurs in both cases.

I'm running the webpack dev-server, and use it somewhere:

import * as React from "react"
import GenericInstance from "path/to/GenericInstance"

export default MyComponent extends React.Component {
    render() {
        var { typedField } = GenericInstance
        return (
            <main>
                <p>{typedField.myField1} {/* ok */}</p>
                <p>{typedField.myField2} {/* ok */}</p>
            </main>
        )
    }
}

After that I'm adding a new field into my template.json:

{
    "myField1": "",
    "myField2": "",
    "myField3": ""   
}

Saving it. webpack dev-server picks up this change in template.json. Allright. One important thing is that autocomplete of VSCode works (it shows this myField3 in list of available fields). Fine.

At this moment, when I'm trying to use myField3 in MyComponent (like <p>{typedField.myField3}</p>), awesome-typescript-loader sends an error during compilation:

Property 'myField3' does not exist on type '{ "myField1": string; "myField2": string; }'

Obviously, awesome-typescript-loader did not pick up changes in template.json which is used as type in my GenericClass.

How can I beat it? After restart of the dev-server it works fine until I make changes in template.json.

Partial webpack.config.js, package.json and tsconfig.json

config = {
    rules: {
        {
            test: /\.tsx?$/,
            loader: "awesome-typescript-loader",
            exclude: /node_modules/
        },
        {
            enforce: "pre",
            test: /\.js$/,
            loader: "source-map-loader"
        },
    }
}
{
    "devDependencies": {
        "awesome-typescript-loader": "^5.2.1",
        "source-map-loader": "^0.2.4",
        "typescript": "^3.3.3",
        "webpack": "^4.29.3",
        "webpack-cli": "^3.2.3",
        "webpack-dev-server": "^3.1.14"
    }
}
{
    "compilerOptions": {
        "module": "esnext",
        "target": "es5",
        "moduleResolution": "node",
        "baseUrl": "src",
        "allowSyntheticDefaultImports": true,
        "noImplicitAny": true,
        "strict": false,
        "sourceMap": true,
        "outDir": "dist/",
        "jsx": "react",
        "traceResolution": true,
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "allowJs": true,
        "declaration": false,
        "removeComments": true,
        "noLib": false,
        "preserveConstEnums": true,
        "suppressImplicitAnyIndexErrors": true,
        "types": [ "node" ],
        "lib": ["es6", "dom", "dom.iterable"],
        "downlevelIteration": true,
        "resolveJsonModule": true,
        "typeRoots": [
            "./node_modules/@types"
        ]
    },
    "include": [
        "src/**/*"
    ]
}

Update

I can confirm that this occurs only with imported *.json. Probably, the problem can be in touch with resolveJsonModule setting for TypeScript, but not sure. Setting useCache and usePrecompiledFiles to false explicitly for awesome-typescript-loader in webpack.config.js does not help. I mean, changed webpack.config.js now looks like:

{
    test: /\.(t|j)sx?$/,
    loader: "awesome-typescript-loader",
    options: {
        useCache: false,
        usePrecompiledFiles: false
    },
    exclude: /node_modules\/(?!superagent)/,
},
Tradein answered 14/2, 2019 at 16:49 Comment(11)
Maybe the caching behaviour of modules is different when using json files as modules in typescript. Could you change that json file to a typescript module / object literal and export that?Bactericide
@DerAlex Thank you for your comment. AFAIK, caching of files in atl is disabled by default. I understand what are you saying about, and, possibly, this is true, but if it is true, then, seems like, there is no way to fix it (according to atl docs). It will be hard for me to swap json with module or object literal, because a lot of things is dependent on it, but I will try :)Tradein
@DerAlex but I suppose it is not necessary to check it, because atl works clearly fine on changing of .(j|t)sx?$ filesTradein
@LevitatorImbalance Did you try this configure?: At webpack.config.js loader: 'awesome-typescript-loader' options: useCache: false, usePrecompiledFiles: false. Please double check because default is false.Underwent
@QuỳnhNguyễn useCache and usePrecompiledFiles are false by default (according to official docs), but I just forced this config and... nothing changed.Tradein
"After that I'm adding a new field into my template.json:" You missed a comma in the JSON bellow this sentenceDeification
@Deification suggest an edit, I'll accept it :)Tradein
So it was just a typo in your question, then ?Deification
@Deification yes, definetly, just a typo. I created code in this question from the scratch)Tradein
@Deification oh, you have a privilege to edit questions without confirmation!Tradein
Yes, you can edit questions and answers without waiting for approval after you reach 2000 points.Deification
T
3

This is a bug in awesome-typescript-loader. As of v5.2.1, here's a quick fix:

// node_modules/awesome-typescript-loader/dist/instance.js

// ln: 214:
- var EXTENSIONS = /\.tsx?$|\.jsx?$/;
+ var EXTENSIONS = /\.tsx?$|\.jsx?|\.json$/;

Apparently the author forget to include .json extension as a valid target.

Tabaret answered 1/4, 2019 at 14:49 Comment(9)
PR fired: github.com/s-panferov/awesome-typescript-loader/pull/629Tabaret
Thank you for your answer. I'm modified the file you have referred, but it did not solve the problem :(Tradein
@LevitatorImbalance That's weird. I was able to reproduce the error as per your description, and I solved mine by modified that line. Must be some other difference in our setup?Tabaret
You might want to put a console.log in that instance.js file to check if it's the actual source file used by the at-loader instance.Tabaret
Well, checked all, extensions are modified. Changed import * as template from "template.json" to import template from "template.json" and the issue disappeared. But your solution and pull request are totally right. Thank you!Tradein
However, I found something weird. It works only after triggering the OP error at once. I mean: Start server -> Manage template.json -> Save (changed ARE NOT being picked up) -> Use new field (error triggered) -> Manage template.json -> Save (changes ARE being picked) -> Use both new fields -> Everything is ok.Tradein
at-loader use a "checker" in other process to ts-check your code. Unlike tsc, it doesn't use native fs. Instead it uses webpack's internal virtual fs. This explain the diff in behavior.Tabaret
Basically at-loader listen to changes in webpack's fs, filter to keep only ts related changes, then call checker.updateFile() for each changed file. In that instance.js you can log to see what "changes" are feed to checker to further pin point the problem.Tabaret
Well, what I can see and confirm, that watchRun hook does not reacting on first save at all. I console.logged the fileName inside changedFiles.map, and it does not being triggered during first save-update. It DOES emit changes for ts files, but does not for json on first load. After further updates everything is ok. Pretty strange thing. Well, thank you once more time, you solved a big problem)Tradein

© 2022 - 2024 — McMap. All rights reserved.