-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Skip typechecking; only emit (support --transpileOnly
in tsc
, re-open of #4176)
#29651
Comments
--transpileOnly
in tsc
, re-open of #4176)
I noticed the questions in #30117 and would like to give some answers for context:
If this has to do with
I realize that I haven’t put the diagnostic information in the issue. This is the diagnostic info for incremental compilation.
Here’s the corresponding CPU profile: As you can see, about 80% of “Check time” is spent in
This is a module project, but (cc: @RyanCavanaugh) |
Discussed. We felt like we had a good handle on this and then totally deadlocked on the question of whether this mode would imply
Separately, the problem that this mode only "works" if Ultimately a tool that just calls We were curious if things got better for you with |
I would add another reason c) treat all ts errors as warnings and still emit the results. The advantage of this workflow is that it enables faster prototyping when combined with hot reload / run on save. You can see type errors alongside runtime errors and get the best of both worlds. You still care about ts errors as they show up in your IDE and build logs but they do not necessarily break your build. This may not be desired on all projects or environments but that's where the flag comes in. I would suggest to add a |
|
Discovered |
This should be included in tsc as `--transpileOnly` flag
…On Mon, Jun 24, 2019, 07:50 Ben Lu ***@***.***> wrote:
Discovered typescript-transpile-only guess this solves my problems:
https://github.com/cspotcode/typescript-transpile-only
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#29651?email_source=notifications&email_token=ABHLQMG5MAGNM2PWKEJD7PDP4BOBJA5CNFSM4GTLYFDKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYL2RAA#issuecomment-504866944>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABHLQMC5IOHUUBHISY3BKBLP4BOBJANCNFSM4GTLYFDA>
.
|
Another reason this would be great is compiling in the production environment. In production we don't install dev dependencies, so running |
My use case is quickly transiling typescript snippet so I can use it in non-typescript project. Currently I need to use online playground for this... |
There is feedback for Deno that having a transpile only option might be a viable way to speed up startup of some workloads (denoland/deno#3321) While we cache the output of a compile, if you are loading some known good TypeScript for the first time, just parsing and emitting, and not type checking, might be a good option. |
@kitsonk if you have code you assume is "known good", why not add some more into that definition of "known good", rather than just "was type checked", and support shipping and loading a bytecode? Kinda like |
@weswigham that is something @ry and I talked about, V8 does have a byte code type format that we could cache instead of even JavaScript. But let's say you were consuming a source module that your instance of Deno hasn't cached yet. You would go to a well maintained source, that you know us valid and injest it, and all you want out is the "bytecode" as fast as you can. Personally I wouldn't want to do it that way, I would always want to spend a few cycles checking the code, but I guess I can see an "just erase the types" emit only as supporting some types of workloads. |
🤷♂ Deno uses the |
@weswigham 😊 um... yeah... 🤦♂ sorry for the noise. |
@canvural my workaround is to compile the project locally than rsync the dist to the server |
I've got 2 more use cases. One has to do with performance in a CI/CD pipeline, the other has to do with mutation testing. CI/CDLet's say your CI/CD pipeline looks like this:
When
Depending on the duration caching between build jobs (gitlab ci does a good job at this) this saves minutes per pipeline. Mutation testingLet's say you're building a mutation testing framework that supports typescript (something like Stryker mutator, which I am maintainer of) and you're planning to implement mutation switching in order to improve performance (which we're planning to do). You would want to split of type checking and transpiling into separate steps. Let's say you have this statement: const foo = 'bar ' + (40 + 2); The mutation testing framework might want to create 2 mutants here: // mutant 1
const foo = 'bar ' - (40 + 2);
// mutant 2
const foo = 'bar ' + (40 - 2); Note that mutant 1 results in a compile error, since in TypeScript When using mutation switching, the mutation testing framework will make 1 version of the code that contains both mutants. Like so: let foo;
switch(global.activeMutant) {
case 0:
// mutant 1
foo = 'bar ' - (40 + 2);
break;
case 1:
// mutant 2
foo = 'bar ' + (40 - 2);
break;
} The mutation testing framework will now test both mutants. First it will type check (using the type checker api) and if valid, run tests for that mutant. The model of transpiling once and in the background type checking all mutants individually saves a lot of time over compiling each mutant indivually, since the test runner process will not have to load in new files at all.
Writing such a tool might not take that much time, but writing and maintaining a drop in replacement will take a lot of time. Just think about the CLI changes between releases. A daunting task if you ask me. |
It was my first time of writing babel config. So {
"presets": [
["@babel/preset-env",
{
"targets": {
"node": 10
}
}
]
],
"plugins": [
"@babel/plugin-transform-typescript"
]
} execution: babel-node --extensions .ts -- index.ts |
I didn't check yet ts-node --transpile-only |
I found a workaround that might work for some use cases. It works by prefixing every file content with // my-little-builder.js
const compiler = ts.createSolutionBuilder(ts.createSolutionBuilderHost(
{
...ts.sys,
readFile(fileName, encoding = 'utf8') {
if (fs.existsSync(fileName)) {
let content = fs.readFileSync(fileName, encoding);
if (!fileName.includes('node_modules') && fileName.endsWith('.ts')) {
content = '// @ts-nocheck\n' + content;
}
return content;
}
}
},
ts.createEmitAndSemanticDiagnosticsBuilderProgram,
(d) => console.log(ts.formatDiagnosticsWithColorAndContext([d], {
getCanonicalFileName: fileName => fileName,
getCurrentDirectory: process.cwd,
getNewLine: () => os.EOL
})),
(status) => console.log(`status: ${status.messageText}`),
(summary) => console.log(`build summary: ${summary}`)
), ['tsconfig.json'], {});
const exitStatus = compiler.build();
console.log(`Exit status: ${exitStatus}`); @RyanCavanaugh What do you think of allowing users to set a global Note: This does not allow for notable performance improvement:
|
We have a similar setup in AWS SDK for JavaScript (v3) and an option to skip type checks while compiling non-types artifacts (CJS/ESM) will help us improve build speeds. |
So useful for npm ci |
|
If you want to transpile the typescript project into javascript without type checking, you can use esbuild, it runs very fast. |
We output multiple targets: commonjs and esmodule |
When I build multi-target project, I use esbuild to build js in common js, esm, and browser bundle. Then use tsc to build .d.ts file (only the last step has type checking). With run-p in npm-run-all, the two build steps can be run in parallel. When I build node.js-only project, I use tsc to build js and .d.ts in one pass. |
any updates on this? there's plenty of tools that can do this in the meantime, but i'd prefer as little dependencies as possible. this here is basically the same use case as i have multiple times in my projects. would really be very convenient |
3 days shy of a year later, do we have an answer yet? |
Just saw @y-nk 's comment. I would like to note that the package I wrote takes advantage of the node_modules folder. I've been doing a lot more with yarn pnp recently and think there would need to be some additional lift for that. I don't currently have the time to add that configuration but anyone who would like to play with that need, can. |
I published a cli package live-tsc that do transpiling without type checking. It is a recursive wrapper built on top of esbuild, with support on watch mode and adding custom post-hook. |
We use direct Git repo references for our packages and we ended up with the following ESBuild script for emitting CJS, ESM and declaration files upon package installation (postinstall) (inspired by @beenotung's script): #!/usr/bin/env node
const esbuild = require('esbuild');
const { nodeExternalsPlugin } = require('esbuild-node-externals');
const tsPaths = require('esbuild-ts-paths');
const { globPlugin } = require('esbuild-plugin-glob');
const { dtsPlugin } = require("esbuild-plugin-d.ts");
Promise.all([
esbuild.build({
entryPoints: ['./src/**/*.ts', './src/**/*.tsx'],
outdir: 'dist',
bundle: false,
minify: true,
format: 'cjs',
platform: 'node',
sourcemap: true,
sourcesContent: false,
jsx: 'automatic',
target: 'node12',
plugins: [dtsPlugin(), globPlugin(), tsPaths('./tsconfig.json'), nodeExternalsPlugin()],
}),
esbuild.build({
entryPoints: ['./src/**/*.ts', './src/**/*.tsx'],
outdir: 'dist/es',
bundle: false,
minify: true,
format: 'esm',
platform: 'node',
jsx: 'automatic',
sourcemap: true,
sourcesContent: false,
target: 'node14',
plugins: [dtsPlugin(), globPlugin(), tsPaths('./tsconfig.json'), nodeExternalsPlugin()],
}),
]).catch((error) => {
console.error(error);
process.exit(1);
}); Obviously, it adds a bit of overhead to have |
Use case: trying to compile some random repo that has out of date typedefs. Not my code, and I just need to transpile and run the thing to get a result. I frankly had no idea up until this minute that transpileOnly was ts-node! I had assumed all along that it was a tsc feature. |
Maybe another use case. My company uses a monorepo with pnpm. All our pnpm workspaces are written in typescript, and we have to build them before they'll work when installed in other packages. We know all these packages were already typechecked in ci. What I want to do is build with esbuild, and generate .d.ts files with tsc. I'm wondering if skipping the type checking here would speed up the .d.ts file generation any significant amount. |
One more use case All my tests has written in TS and obviously Nodejs can't execute it without precompilation into JS. I can do this in this way: node --import ./node_modules/typescript/bin/tsc --test ./src/**/*.test.ts", My code is not perfect and contain a bunch of type errors and it is OKAY. For typeschecking I have another solution so in my tests I would test only my code not types. For that it would be great if there exists CLI command like |
TypeScript 5.5 added |
I believe it's not user-facing in 5.5, even on the API level. #58839 makes it broadly accessible though, so we can mark this as fixed. |
Oops, typo, I meant 5.6! |
Search Terms
isolatedModules, incremental build slow, allowJs, transpileOnly. #4176
Suggestion
Support a compilation mode where files are only transpiled without typechecking. This can greatly improve compilation speed. Similar to the
transpileOnly
flag ints-node
andts-loader
.Use Cases
At @taskworld, we are trying to migrate our project to TypeScript. We have 1400 source files.
As we try to get our
.js
files to be processed and transpiled bytsc
, setting"allowJs": true
makestsc
take a painfully long time (40 seconds) to complete, even in--watch
mode.tsc --diagnostics
shows that lots of time is spent in typechecking phase.I have checked these issues:
typescript --allowJs too slow #7808
No resolution.
2x compilation slowdown when upgrading from TS1.8 => TS2.0 #10018
Irrelevant — compiler speed has since been improved but that did not solve our problem.
TypeScript Extremely Slow #21221
I used
tsc --listFiles
to check the files included in the compilation unit. Looks normal. In that issue, they solved the problem by renaming all.js
to.ts
, which we can’t do yet without causing errors all over the place, due to our JS files are still CommonJS modules, which is only recognized when using JS files. I try to migrate with minimal code changes, so I avoid mass-converting CommonJS to ES modules for now.Strategies for improving incremental Check time? #13538
People at Google solved this problem by separating their project into libraries and creates their own build system (based on Bazel). Since I tried to add the tooling with minimal code change, we don’t want to “split our code base into multiple units” right now.
Very slow compilation with allowJs #10157
OP solved this problem by using
transpileOnly
mode ints-loader
, which uses the “single-module transpilation mode” (thets.transpileModule
API). However, we aren’t usingwebpack
and we’re directly usingtsc
to compile.ts
files to.js
files.TypeScript build is slow, compileOnSave/--watch taking ~1minute #22953
No resolution.
I tried to profile the
tsc
process, and found that a lot of time is spent inresolveCallSignature
.If we can skip the type-checking process, this compilation phase should be faster.
This seems to be supported in both
ts-node
andts-loader
, since TypeScript provides the “single-module transpilation mode” (thets.transpileModule
API). So, I looked for a way to do it usingtsc
. Turns out, it is not available, and we have to somehow use thets.transpileModule
API directly.#4176 (comment)
#13538 (comment)
Examples
All evidence so far suggests that we have to build our own tooling which behaves like
babel -d build-dir source-dir
(e.g. compiles each file separately) but for TypeScript. And so we implemented our own workaround:To typecheck in separate step, we simply run
tsc --noEmit
in a separate CI job. Also, VS Code takes care of typechecking in the editor, so we already get instant feedback for type errors.Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: