Skip to content

Very slow builds with many types (especially vue single file components) #988

@WolfspiritM

Description

@WolfspiritM

Expected Behaviour

Fast compile

Actual Behaviour

Very slow compile

Steps to Reproduce the Problem

Check out https://github.com/WolfspiritM/TypeScript-Vue-Starter
Run "npm install" and "npm run build"
Compile takes more then 30 Seconds (48 Seconds in my case).
The project has about 40 very simple SFCs and has types loaded (especially lodash-es seems to cause troubles as it is so big I think).

I debugged the reason for the very slow build and found out that ts-loader is trying to compile every single file it receives from webpack. That in itself isn't a problem but for each file the languageservice creates a new program with the call to getProgram(). Everytime it creates a new program it reuses ALL files it ever read before (https://github.com/TypeStrong/ts-loader/blob/master/src/servicesHost.ts#L105) as rootfiles (https://github.com/microsoft/TypeScript/blob/825d8bb1dc0c5bae2c0996e538825111f65d07dd/src/services/services.ts#L884) and creates a sourcefile from it which ends up becoming very very slow. The rootfiles array includes for example d.ts files from node_modules aswell.

For normal projects getProgram() will not return a new program cause the rootfiles didn't change from the initial files. Usually all included files are loaded by reading include, exclude and files results from tsconfig but for vue this doesn't work as tsconfig only reads *.ts or *.tsx files.

Any idea how this could be handled better?

I tried to exclude node_modules from getScriptFileNames which seems to have made it a bit faster but the best solution I think would be to somehow resuse the old program. The reason why it doesn't reuse it is that the files root files change.

This is what a did for testing. It made the compiling 20 Seconds faster but not sure if this might break something:

    const filesCache = new Map(files);
    const servicesHost = {
        getProjectVersion: () => `${instance.version}`,
        getProjectReferences: () => projectReferences,
        getScriptFileNames: () => [...files.keys()].filter(filePath => filePath.match(scriptRegex)),
        getScriptVersion: (fileName) => {
            fileName = path.normalize(fileName);
            const file = files.get(fileName);
            return file === undefined ? '' : file.version.toString();
        },
        getScriptSnapshot: (fileName) => {
            // This is called any time TypeScript needs a file's text
            // We either load from memory or from disk
            fileName = path.normalize(fileName);
            let file = filesCache.get(fileName);
            if (file === undefined) {
                file = files.get(fileName);
                if (file === undefined) {
                    const text = utils_1.readFile(fileName);
                    if (text === undefined) {
                        return undefined;
                    }
                    file = { version: 0, text };
                    filesCache.set(fileName, file);
                }
            }
            return compiler.ScriptSnapshot.fromString(file.text);
        },

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions