Closed
Description
I'm using this thread to dump my brain and to note problems as I solve them (or to discuss).
Issues of note:
- Determining Module Migration and Shipping Strategy #49037
- Reduce typescript package size #27891
- Module conversion work #46744 (Eli's old notes)
- Migrate the TypeScript Project to Use Modules #35210
- Module conversion #46567
2022-05-31
Changes since the previous effort
- The "typeformer" (the code that does the transform) now lives at https://github.com/jakebailey/typeformer, and has been rewritten using ts-morph to preserve comments and formatting.
- The old typeformer use TS's own transform and emitter, but the emitter is not careful enough to preform TS-to-TS transformations (I have a list of bugs I've discovered, which don't matter for JS emit)
- My WIP changes are semi-automatically pushed to a stack of PRs on my fork, starting here.
- It's "best" to look at the difference between the "indent" commit and the last commit, e.g. this diff (but note that this link may not be up to date, is is as of now).
- Please don't comment on these PRs; the script I run to create this stack is not very smart and will force-push if I insert a new commit in the middle. I wish I could just use
gerrit
, but...
- I have removed the esbuild step from the previous effort; not because we don't plan to use it, but because it's simplest to start by using raw modules and then tweaking the output later. If we're going to be modules, I'd hope we can be run through a bundler successfully.
- The faked namespace modules (barrel modules that at runtime behave very similarly to the old namespaces) have been moved to a dedicated folder in each project, rather than being dumped at the top level.
- Use webworker typings for webServer.ts #46944 has to be reverted; this code doesn't seem to compile properly when actually built.
typeformer bugs
- The typeformer's
inlineImports
step convertsglobalThis.assert
intoassert
, because it thinks it's a global function that should be settable. Technically true, but if we wanted that, we probably wouldn't have writtenglobalThis
explicitly. This is just a bug when I rewrote the step. - Sometimes
#region
comments are dropped. Likely a bug that can be worked around like other ts-morph oddities to do with comment preservation (which it is almost always good at, but sometimes not). - Sometimes comments get duplicated, e.g.
// DestructuringAssignmentType
insrc/compiler/types.ts
. - The output path is determined by the project name; this was changed in my iteration of the typeformer, but should be hand-tweaked back to the right path, e.g. the debug code (
dbg.ts
) that is dynamically loaded in, orloggedIO
.
Unsolved problems
- My version of the typeformer's "inlineImports" pass is very aggressive, importing everything from their original declaration if possible. This is closest to how we would write the code by hand (if we had done so from the start), but the circularity of the codebase has broken things.
- e.g.,
debug.ts
importssemver.ts
, but theSemver
class creates a static propertyzero
, which calls theSemver
constructor, which then containsDebug.assert
calls. - This only happened because the top of
debug.ts
containsimport { Semver } from './semver
, whereas before, the code didn't do this but instead referred to the namespace, so never actually caused that file to be evaluated. - It's totally possible that we'd hit this circularity issue today, except that most code is not at the top level and avoids the problem entirely, or has worked "magically" thanks to the order we happen to merge namespaces in.
- We could just import these from the namespaces (like Module conversion #46567 does), which I think would fix this, but this is really unnatural code structure and auto-imports will not function properly.
- e.g.,
- The
System
interface (akats.sys
) is set (ts.sys = ...
) in order to support the browser, but in the module version, modules doimport { sys } from '...'
), which makes it very difficult to do like this. What can do do here? - Additionally, the
System
interface hasgetExecutingFilePath
(among other functions), which only makes sense for TS packaged as a self contained file.
TODOs
- Figure out what to do about the API; the past effort talks about API extractor, which is the right thing to do, but we need to make sure that we produce an output that describes the API as namespaces, not as reexported modules. Re-export class from namespace #4529 makes this hard.
- We need to create the entrypoints for the new exported API; right now it just outputs as
outDir
, but I don't think we intend to just allow everyone to import our internals directly.outFile
made a file that did the right thing before, and after we just need to write something liketsc.js
which exports*
from_namespaces/ts.ts
or something.- See also
exportAsModule
, which hacks together amodule.exports = ...
line rather than emitting it viaexport
.
- See also
- Deprecations were previously done via namespace merging (i.e. deprecating "Map" in favor of "ESMap"); these are very messy when not coming up with a single file.
-
registerRefactor
uses side effects of file loading to register refactorings. This technically works OK after modification if the fake namespace modules still import these files, but it'd be better to refactor this to work like the transforms (which are just imported in other files instead). - Loads of type names are duplicated; this previously didn't matter because you'd just fully qualify names for another namespace, but now that things are directly imported, you end up with these random fully-qualified names which would be better done differently. For example,
fakeHosts.ts
implements certain interfaces, but does so with classes named the same as the interface. Maybe just doFakeSomeInterface
?
Other stuff
- We should be able to hide the big refactor when it's merged using a
.git-blame-ignore
file. See: