Repository navigation
Support using --module and --outDir flags in conjunction with --build #26763
Description
Search Terms
--build --module --outDir
Suggestion
I would like to be able to pass --module and --outDir, in --build mode so that I can have multiple npm scripts for different build outputs without needing multiple tsconfig files.
Use Cases
In Aurelia vNext we've fully adopted the new 3.0 build system and are starting to prepare for publishing. We want to publish the build outputs for all different module systems (for all packages) so that consumers can easily point to the one that's compatible with their project.
We have been able to do this pre-3.0 like so:
"build:commonjs": "tsc -m commonjs --outDir dist/commonjs",
"build:amd": "tsc -m amd --outDir dist/amd",
"build:system": "tsc -m system --outDir dist/system",
"build:umd": "tsc -m umd --outDir dist/umd",
"build:es2015": "tsc -m es2015 --outDir dist/es2015",Now when trying to do this, it doesn't work:
"build:commonjs": "tsc -b -m commonjs --outDir dist/commonjs",
"build:amd": "tsc -b -m amd --outDir dist/amd",
"build:system": "tsc -b -m system --outDir dist/system",
"build:umd": "tsc -b -m umd --outDir dist/umd",
"build:es2015": "tsc -b -m es2015 --outDir dist/es2015",
"build:esnext": "tsc -b -m esnext --outDir dist/esnext",Results in:
message TS6096: File (...)/packages/runtime/-m' does not exist
message TS6096: File (...)/packages/runtime/commonjs' does not exist
And nothing else happening. I read in the docs that only 4 particular flags are supported in conjunction with --build so it seems this is simply not implemented.
Examples
We'd like to have something like this in the packages package.json:
"build:commonjs": "tsc -b -m commonjs --outDir dist/commonjs",
"build:amd": "tsc -b -m amd --outDir dist/amd",
"build:system": "tsc -b -m system --outDir dist/system",
"build:umd": "tsc -b -m umd --outDir dist/umd",
"build:es2015": "tsc -b -m es2015 --outDir dist/es2015",
"build:esnext": "tsc -b -m esnext --outDir dist/esnext",
"build": "run-p build:*",
And when calling npm run build from the top-level package (using lerna...), that would produce build outputs in all module formats for all packages
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript / JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. new expression-level syntax)
Activity
raymondfeng commentedon Aug 30, 2018
My understanding is that these flags should be set by each referenced projects (in tsconfig). Think about a build that brings in more than one modules and it does not make sense to have a (global) CLI option.
EisenbergEffect commentedon Aug 31, 2018
For an example setup, you'll need to look at the Aurelia Monorepo. We have a number of packages that we have to build with a single command, all of which need to output every format. Each package has the same configuration, but we now have to duplicate tons of tsconfig.files all over the place, 6 * NumberOfPackages. In our case, that's 36+ tsconfig files instead of 6. Each time we add a new package to our monorepo, we have to add 6 more copies. It's not good for maintenance in real-world monorepo setups.
fkleuver commentedon Aug 31, 2018
In the case of multiple module outputs per package, there is no functional difference between setting this in the tsconfig versus setting it in a cli flag.
Example setup
Consider the scenario with two packages
package-fooandpackage-bar, and two different module outputscommonjsandamdpackage-footsconfig.jsonsays"module": "commonjs"tsconfig.amd.jsonsays"module": "amd"package.jsonsays"main": "dist/commonjs/index"package-barpackage-fooBuild steps
Now we run
tsc -binpackage-bar, the following happens:package-barsees the dependency onpackage-foopackage-foois built; output goes topackage-foo/dist/commonjspackage-baris built, referencingpackage-foo/dist/commonjs; output goes topackage-bar/dist/commonjsThen we run
tsb -b tsconfig.amd.jsoninpackage-bar, this happens:package-barsees the dependency onpackage-foopackage-foois built; output goes topackage-foo/dist/commonjspackage-baris built, referencingpackage-foo/dist/commonjs; output goes topackage-bar/dist/amdResult
package-bar, by all means and purposes, is fine now. The outputs are not combined, so the fact that the commonjs build outputs ofpackage-foowere used to produce the AMD outputs ofpackage-barisn't noticeable in any way.In a next sequential step we build
package-fooin the same manner, and now we have both module outputs for both packages. Problem solved.A consumer who needs the non-default module output would typically have the installation/configuration going through our cli which can make sure all packages are referencing the same module output.
The identical effect could by achieved by passing the cli arguments to
tsc -bikokostya commentedon Sep 5, 2018
Related to #25613
fkleuver commentedon Sep 6, 2018
Ryan Cavanaugh (@RyanCavanaugh) I would be OK with closing this as a duplicate of #25613 if that makes things easier for you guys. Essentially my issue boils down to the same thing, it's just specific to some particular flags. Up to you
RyanCavanaugh commentedon Sep 17, 2018
Fred Kleuver (@fkleuver) thanks - I think these deserve separate issues since the "mixing" mode would probably naturally exclude per-project-computed things like outdir and rootdir. This scenario is complex enough to warrant its own behavior
screendriver commentedon Nov 14, 2018
Just a side note because I have the same problem:
AVAjust can handle that for running testswebpackbundling after the tests the files should be in ECMAScript modules because it has more advantages there.Now when I run
tsc -b, run my unit tests over that and after that do atsc -b tsconfig.esm.jsonfor the webpack build, nothing changes in my output directory because I didn't touch any files so the type declarations stay the same. As a workaround I could introduce two different output directories. One for ESM and one for CommonJS but this feels a little bit hacky. Or, as I do it at the moment, completely ignore ESM and just compile to CommonJS all the time.