スキップしてメイン コンテンツに移動

[TypeScript] Read source code of tsc 2(incremental)

Intro

[TypeScript] About tsconfig 1
[TypeScript] Read source code of tsc 1(Parse options)

The result of parsing, the instance of BuildOptions is created.

compiler/tsbuildPublic.ts


    export interface BuildOptions {
        dry?: boolean;
        force?: boolean;
        verbose?: boolean;

        /*@internal*/ clean?: boolean;
        /*@internal*/ watch?: boolean;
        /*@internal*/ help?: boolean;

        /*@internal*/ preserveWatchOutput?: boolean;
        /*@internal*/ listEmittedFiles?: boolean;
        /*@internal*/ listFiles?: boolean;
        /*@internal*/ pretty?: boolean;
        incremental?: boolean;
        assumeChangesOnlyAffectDirectDependencies?: boolean;

        traceResolution?: boolean;
        /* @internal */ diagnostics?: boolean;
        /* @internal */ extendedDiagnostics?: boolean;
        /* @internal */ locale?: string;
        /* @internal */ generateCpuProfile?: string;

        [option: string]: CompilerOptionsValue | undefined;
    }

It includes "incremental".
So this time, I read about "incremental".

Who uses "incremental"?

The "incremental" is eventual used in tsbuildPublic.ts's needsBuild.

compiler/tsbuildPublic.ts


    function needsBuild({ options }: SolutionBuilderState, status: UpToDateStatus, config: ParsedCommandLine) {
        if (status.type !== UpToDateStatusType.OutOfDateWithPrepend || options.force) return true;
        return config.fileNames.length === 0 ||
            !!getConfigFileParsingDiagnostics(config).length ||
            !isIncrementalCompilation(config.options);
    }

compiler/utilities.ts


...
    export function isIncrementalCompilation(options: CompilerOptions) {
        return !!(options.incremental || options.composite);
    }
...

!!

I have never seen "!!". What's this?
The result is "if options.incremental or options.composite (or both) is true, it returns true".
In this context, "!!" does nothing.

But if the values aren't boolean type?

const incremental = false;
const composite1 = undefined;
const composite2 = 'hello';
const composite3 = 2
const composite4 = [2];

console.log('RESULT: undefined');
console.log((incremental || composite1));
console.log('RESULT: string');
console.log((incremental || composite2));
console.log('RESULT: number');
console.log((incremental || composite3));
console.log('RESULT: array');
console.log((incremental || composite4));

The results are ...
[LOG]: RESULT: undefined 
[LOG]: undefined 
[LOG]: RESULT: string 
[LOG]: hello 
[LOG]: RESULT: number 
[LOG]: 2 
[LOG]: RESULT: array 
[LOG]: [ 2 ] 
The types are changed from boolean.
For avoiding this, I can use "!!".

const incremental = false;
const composite1 = undefined;
const composite2 = 'hello';
const composite3 = 2
const composite4 = [2];

console.log('RESULT: undefined');
console.log(!!(incremental || composite1));
console.log('RESULT: string');
console.log(!!(incremental || composite2));
console.log('RESULT: number');
console.log(!!(incremental || composite3));
console.log('RESULT: array');
console.log(!!(incremental || composite4));

The results are ...
[LOG]: RESULT: undefined 
[LOG]: false 
[LOG]: RESULT: string 
[LOG]: true 
[LOG]: RESULT: number 
[LOG]: true 
[LOG]: RESULT: array 
[LOG]: true 
What's the double exclamation mark for in JavaScript? | Brian F Love

UpToDateStatus

In needsBuild function, I think "status.type" makes tsc build after the TypeScript file updated.
Because the remaining conditions are "force" option or about existence of config file.

So I'm following the UpToDateStatus.

It's set by getUpToDateStatus in getNextInvalidatedProject of tsbuildPublic.ts.

compiler/tsbuildPublic.ts


...
    function getNextInvalidatedProject<T extends BuilderProgram>(
        state: SolutionBuilderState<T>,
        buildOrder: AnyBuildOrder,
        reportQueue: boolean
    ): InvalidatedProject<T> | undefined {
...
            const status = getUpToDateStatus(state, config, projectPath);
            verboseReportProjectStatus(state, project, status);
...
            return createBuildOrUpdateInvalidedProject(
                needsBuild(state, status, config) ?
                    InvalidatedProjectKind.Build :
                    InvalidatedProjectKind.UpdateBundle,
                state,
                project,
                projectPath,
                projectIndex,
                config,
                buildOrder,
            );
        }

        return undefined;
    }
...
    function getUpToDateStatus(state: SolutionBuilderState, project: ParsedCommandLine | undefined, resolvedPath: ResolvedConfigFilePath): UpToDateStatus {
        if (project === undefined) {
            return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" };
        }

        const prior = state.projectStatus.get(resolvedPath);
        if (prior !== undefined) {
            return prior;
        }

        const actual = getUpToDateStatusWorker(state, project, resolvedPath);
        state.projectStatus.set(resolvedPath, actual);
        return actual;
    }
...


Because state.projectStatus is undefined this time, so I think state.projectStatus will be set by getUpToDateStatusWorker.

compiler/tsbuildPublic.ts


...
    function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus {
...
        let pseudoUpToDate = false;
        let usesPrepend = false;
        let upstreamChangedProject: string | undefined;
        if (project.projectReferences) {
            // tsc executes here only when I add "watch" option
        }
...
        // if tsconfig.json's modified time is newer than tsconfig.buildinfo, "isOutOfDateWithInputs" becomes true
        if (isOutOfDateWithInputs) {
            return {
                type: UpToDateStatusType.OutOfDateWithSelf,
                outOfDateOutputFileName: oldestOutputFileName,
                newerInputFileName: newestInputFileName
            };
        }
        else {
            // if there are multiple output files, 
            // and if tsconfig.json's modified time is newer than the oldest output file, the type is set as "UpToDateStatusType.OutOfDateWithSelf".
            // Check tsconfig time
            const configStatus = checkConfigFileUpToDateStatus(state, project.options.configFilePath!, oldestOutputFileTime, oldestOutputFileName);
            if (configStatus) return configStatus;

            // Check extended config time
            const extendedConfigStatus = forEach(project.options.configFile!.extendedSourceFiles || emptyArray, configFile => checkConfigFileUpToDateStatus(state, configFile, oldestOutputFileTime, oldestOutputFileName));
            if (extendedConfigStatus) return extendedConfigStatus;
        }

        if (!state.buildInfoChecked.has(resolvedPath)) {
            state.buildInfoChecked.set(resolvedPath, true);
            const buildInfoPath = getTsBuildInfoEmitOutputFilePath(project.options);
            if (buildInfoPath) {
                const value = state.readFileWithCache(buildInfoPath);
                const buildInfo = value && getBuildInfo(value);
                if (buildInfo && (buildInfo.bundle || buildInfo.program) && buildInfo.version !== version) {
                    return {
                        type: UpToDateStatusType.TsVersionOutputOfDate,
                        version: buildInfo.version
                    };
                }
            }
        }
...
        // Up to date
        return {
            type: pseudoUpToDate ? UpToDateStatusType.UpToDateWithUpstreamTypes : UpToDateStatusType.UpToDate,
            newestDeclarationFileContentChangedTime,
            newestInputFileTime,
            newestOutputFileTime,
            newestInputFileName,
            newestOutputFileName,
            oldestOutputFileName
        };
    }



According to getUpToDateStatusWorker, the condition of setting state.projectStatus as "UpToDateStatusType.OutOfDateWithPrepend" is only when I add "watch" option.
Thus, the first arguments of createBuildOrUpdateInvalidedProject is "InvalidatedProjectKind.Build".

コメント

このブログの人気の投稿

[Nest.js] Show static files

Intro I wanted to use Nest.js and WebRTC(node-webrtc). NestJS - A progressive Node.js framework Documentation | NestJS - A progressive Node.js framework And because I wanted to try with simple page(not use JavaScript frameworks), I added static HTML, CSS, JavaScript into a Nest.js project. Prepare Install First, I installed @nestjs/cli. First steps | NestJS - A progressive Node.js framework As same as last time , I couldn't do global install because I had used Volta. But I could installed by volta. volta install @nestjs/cli Create project nest new nest-web-rtc-sample volta pin node@12 Run npm start After doing "npm start", I could getting "Hello World!" from http://localhost:3000. Add static files I could add static files by two ways. @nestjs/serve-static First one of them was using "serve-static". Serve Static | NestJS - A progressive Node.js framework npm install --save @nestjs/serve-static And I needed adding a module into app.modu

[Angular][ASP.NET Core] Upload chunked files

Intro I wanted to send files to Web application (made by ASP.NET Core). If the file size had been small, I didn't need do any special things. But when I tried to send a large file, the error was occurred by ASP.NET Core's limitation. Though I could change the settings, but I didn't want to do that, because I hadn't known the file sizes what would been actually using. So I splitted the data into chunks first, and sent them. After receiving all chunks, I merged them into one file. There might be some libraries or APIs (ex. Stream API) what did them automatically, but I couldn't find them. What I did [ASP.NET Core] Make CORS enabled [Angular] Split a large file into chunks [Angular][ASP.NET Core] Send and receive data as form data [ASP.NET Core] Merge chunks into one file [ASP.NET Core] Make CORS enabled Because the client side application(Angular) and the server side application(ASP.NET Core) had been separated, I had to make CORS(Cross-Origin Requests)

[Nest.js] Use WebSocket with ws

Intro Until last time , I had used node-web-rtc to try WebRTC. But because the example was a little complicated for I understood the core functions of using WebRTC. So I look for other frameworks or libraries. PeerJS is a famous library for WebRTC. peers/peerjs: Peer-to-peer data in the browser. - GitHub peers/peerjs-server: Server for PeerJS - GitHub PeerJS - Simple peer-to-peer with WebRTC A problem is I don't know how to integrate to the Nest.js project. I couldn't find examples. So I don't choose at least this time. What shall I choose? According MDN, WebRTC doesn't specify strictly what technology is used on server application for connecting two devices. Signaling and video calling - Web APIs | MDN But in many examples include MDN's one use WebSocket. samples-server/s/webrtc-from-chat at master · mdn/samples-server · GitHub So I try WebSocket in the Nest.js project. Use WebSocket in a Nest.js project Nest.js has a function for using We