Skip to content
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

Use babel to transpile TS projects #47502

Merged
merged 13 commits into from Nov 19, 2020
Merged

Use babel to transpile TS projects #47502

merged 13 commits into from Nov 19, 2020

Conversation

scinos
Copy link
Contributor

@scinos scinos commented Nov 17, 2020

Summary of changes

  • Use babel to transpile TypeScript packages at bundle time.
  • Use tsc to check types and generate type definitions.
  • Use build mode to generate types for all packages quickly.

Inspired by the discussion in #47002 by @jsnajdr and @sirreal

Background

Our Babel config can transpile TypeScript files. However we are not using that capability. Instead, we have a script build-packages that runs tsc on each package, creating an ESM compilation. Then that compilation is read by webpack and bundled with the rest of the app. This is not optimal because TypeScript can't do a smarter transpilation based on the target (evergreen vs fallback), and also it wastes time as packages are transpiled twice.

Changes

  • Exposes the untranspiled TypeScript code in TS packages using the property calypso:src that we introduced in Do not transpile JS packages twice #44824. This allows Webpack and babel to read the original TypeScript code and transpile it.

  • Create a build step on each TypeScript package that will generate CJS, ESM and types. This is used on prepack, when the package is being built for publishing.

  • Create a "main" tsconfig.json that references all TS packages, used as an entrypoint for tsc.

Notes

  • We don't really need to run tsc at all for Calypso to compile and work. It is all handled by babel. The only reason to run tsc at installation time is to generate type definitions that can be used by the IDE.

  • In theory we could use just tsc --emitDeclarationOnly to generate the definition files. However, tsc --build also generates the types and it is much faster with a warm cache.

  • I don't think we need watch mode for packages (i.e. build-packages:watch). In my experiments, if you run webpack in watch mode and change a .ts file in a package, webpack will rebuild as expected. Also, if you change a type in a TS package, VSCode will pick the change, no need to rebuild the types. However, cleaning up watch mode is left for a future PR to avoid scope creep.

Testing instructions

  • Verify tests are green, ICFY doesn't show a crazy diff in bundle size and smoke test calypso.live (in Chrome and IE11), specially areas that have been moved to TS packages (eg: language picker, checkout, shopping cart)

  • Checkout this branch and run yarn twice. The second time (deps already installed, nothing to build) should finish in a couple of seconds.

@scinos scinos requested a review from a team as a code owner November 17, 2020 13:01
@matticbot matticbot added the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Nov 17, 2020
@matticbot
Copy link
Contributor

@scinos scinos changed the title Add/babel typescript Use babel to transpile TS projects Nov 17, 2020
"prepublish": "yarn run clean",
"prepare": "tsc --build ./tsconfig.json && tsc --build ./tsconfig-cjs.json",
"watch": "tsc --build ./tsconfig.json --watch"
"clean": "tsc --build ./tsconfig.json ./tsconfig-cjs.json --clean && npx rimraf dist",
Copy link
Contributor Author

@scinos scinos Nov 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tsc --build ... --clean deletes the files but lefts lots of empty dirs, that's why I added npx rimraf dist

@matticbot
Copy link
Contributor

matticbot commented Nov 17, 2020

Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

App Entrypoints (~8266 bytes removed 📉 [gzipped])

name                   parsed_size           gzip_size
entry-main                -12037 B  (-0.9%)    -2075 B  (-0.6%)
entry-gutenboarding       -11229 B  (-0.6%)    -2799 B  (-0.6%)
entry-login                -9422 B  (-1.0%)    -2250 B  (-0.9%)
entry-domains-landing      -5490 B  (-0.9%)    -1142 B  (-0.7%)

Common code that is always downloaded and parsed every time the app is loaded, no matter which route is used.

Sections (~26680 bytes removed 📉 [gzipped])

name                      parsed_size           gzip_size
checkout                     -29381 B  (-1.8%)    -3718 B  (-0.9%)
domains                       -6720 B  (-0.6%)    -1721 B  (-0.6%)
purchase-product              -5888 B  (-2.4%)    -1501 B  (-2.3%)
zoninator                     -5398 B  (-1.7%)    -1610 B  (-1.8%)
purchases                     -3809 B  (-0.4%)     -919 B  (-0.4%)
site-purchases                -3729 B  (-0.4%)     -947 B  (-0.5%)
jetpack-connect               -3587 B  (-0.3%)    -1266 B  (-0.4%)
plans                         -3235 B  (-0.4%)     -696 B  (-0.3%)
migrate                       -2517 B  (-1.6%)     -668 B  (-1.5%)
jetpack-cloud-pricing         -2496 B  (-0.6%)     -649 B  (-0.6%)
woocommerce                   -2494 B  (-0.1%)     -520 B  (-0.1%)
themes                        -1395 B  (-0.4%)     -531 B  (-0.5%)
activity                      -1383 B  (-0.2%)     -492 B  (-0.3%)
settings                      -1357 B  (-0.3%)     -506 B  (-0.4%)
plugins                       -1357 B  (-0.3%)     -473 B  (-0.4%)
backup                        -1352 B  (-0.3%)     -500 B  (-0.4%)
media                         -1349 B  (-0.3%)     -526 B  (-0.4%)
settings-performance          -1324 B  (-0.3%)     -482 B  (-0.4%)
import                        -1299 B  (-0.5%)     -266 B  (-0.4%)
security                       -750 B  (-0.2%)     -266 B  (-0.2%)
theme                          -749 B  (-0.2%)     -273 B  (-0.3%)
help                           -746 B  (-0.1%)     -280 B  (-0.2%)
scan                           -745 B  (-0.2%)     -277 B  (-0.3%)
settings-writing               -718 B  (-0.1%)     -261 B  (-0.2%)
account-close                  -718 B  (-0.2%)     -259 B  (-0.3%)
account                        -718 B  (-0.2%)     -276 B  (-0.3%)
signup                         +717 B  (+0.1%)     -106 B  (-0.1%)
earn                           -717 B  (-0.2%)     -288 B  (-0.3%)
notification-settings          -714 B  (-0.2%)     -272 B  (-0.3%)
marketing                      -713 B  (-0.1%)     -270 B  (-0.2%)
email                          -710 B  (-0.2%)     -268 B  (-0.3%)
reader                         -705 B  (-0.1%)     -272 B  (-0.2%)
site-blocks                    -701 B  (-0.2%)     -267 B  (-0.3%)
privacy                        -701 B  (-0.2%)     -264 B  (-0.3%)
settings-security              -698 B  (-0.2%)     -256 B  (-0.3%)
happychat                      -697 B  (-0.2%)     -266 B  (-0.3%)
stats                          -693 B  (-0.1%)     -257 B  (-0.2%)
me                             -693 B  (-0.3%)     -262 B  (-0.4%)
posts-custom                   -690 B  (-0.2%)     -259 B  (-0.2%)
posts                          -690 B  (-0.2%)     -259 B  (-0.2%)
wp-super-cache                 -686 B  (-0.3%)     -271 B  (-0.4%)
people                         -685 B  (-0.2%)     -242 B  (-0.2%)
google-my-business             -681 B  (-0.2%)     -228 B  (-0.3%)
export                         -679 B  (-0.3%)     -215 B  (-0.3%)
settings-jetpack               -678 B  (-0.3%)     -185 B  (-0.3%)
comments                       -677 B  (-0.1%)     -241 B  (-0.2%)
pages                          -674 B  (-0.3%)     -243 B  (-0.3%)
home                           -674 B  (-0.1%)     -264 B  (-0.2%)
jetpack-cloud-settings         -670 B  (-0.4%)     -218 B  (-0.4%)
settings-discussion            -661 B  (-0.3%)     -247 B  (-0.4%)
hello-dolly                    -657 B  (-0.6%)     -207 B  (-0.6%)
sensei                         -653 B  (-0.6%)     -200 B  (-0.6%)
gutenberg-editor               +279 B  (+0.0%)      +34 B  (+0.0%)
accept-invite                  +107 B  (+0.0%)     -335 B  (-0.2%)
concierge                       -99 B  (-0.0%)      -31 B  (-0.0%)
hosting                         -98 B  (-0.0%)      -35 B  (-0.0%)
customize                       -47 B  (-0.0%)      -24 B  (-0.0%)
preview                         -46 B  (-0.0%)      -24 B  (-0.1%)
sites                           -42 B  (-0.0%)      -21 B  (-0.1%)
jetpack-cloud                   -42 B  (-0.0%)      -21 B  (-0.1%)
devdocs                         -28 B  (-0.0%)       -9 B  (-0.0%)
domain-connect-authorize        -20 B  (-0.1%)       -4 B  (-0.1%)

Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to.

Async-loaded Components (~22061 bytes removed 📉 [gzipped])

name                                                                 parsed_size            gzip_size
async-load-calypso-blocks-editor-checkout-modal                         -29481 B   (-2.6%)    -3785 B   (-1.4%)
async-load-design                                                       -21723 B   (-1.2%)    -4888 B   (-1.1%)
async-load-design-playground                                            -14891 B   (-0.9%)    -3470 B   (-0.9%)
async-load-design-blocks                                                 -9133 B   (-0.3%)    -2136 B   (-0.3%)
async-load-signup-steps-about                                            -4054 B   (-6.9%)    -1369 B   (-7.9%)
async-load-signup-steps-site-topic                                       -3429 B  (-11.8%)    -1126 B  (-13.3%)
async-load-calypso-blocks-editor-launch-modal                            -1561 B   (-1.0%)     -673 B   (-1.6%)
async-load-signup-steps-domains                                          -1327 B   (-0.5%)     -287 B   (-0.4%)
async-load-calypso-post-editor-editor-media-modal                        -1321 B   (-0.4%)     -481 B   (-0.5%)
async-load-calypso-blocks-inline-help-dialog                             -1008 B   (-3.4%)     -322 B   (-3.6%)
async-load-signup-steps-plans                                             -787 B   (-0.3%)     -279 B   (-0.4%)
async-load-signup-steps-plans-atomic-store                                -767 B   (-0.5%)     -275 B   (-0.8%)
async-load-calypso-post-editor-media-modal                                -702 B   (-0.2%)     -253 B   (-0.3%)
async-load-signup-steps-clone-point                                       -678 B   (-0.4%)     -217 B   (-0.6%)
async-load-calypso-components-web-preview-component                       -673 B   (-0.1%)     -262 B   (-0.2%)
async-load-signup-steps-theme-selection                                   -672 B   (-1.0%)     -247 B   (-1.4%)
async-load-calypso-my-sites-sidebar                                       -651 B   (-0.4%)     -234 B   (-0.6%)
async-load-signup-steps-clone-credentials                                 -645 B   (-1.0%)     -232 B   (-1.3%)
async-load-calypso-layout-guided-tours-component                          -629 B   (-0.7%)     -193 B   (-0.8%)
async-load-calypso-components-sites-popover                               -629 B   (-1.0%)     -244 B   (-1.2%)
async-load-signup-steps-user                                              -615 B   (-0.5%)     -232 B   (-0.7%)
async-load-calypso-layout-masterbar-drafts-popover                        -611 B   (-1.3%)     -203 B   (-1.3%)
async-load-quick-language-switcher                                        -604 B   (-0.9%)     -214 B   (-1.1%)
async-load-calypso-blocks-inline-help                                     -603 B   (-0.4%)     -204 B   (-0.5%)
async-load-design-wordpress-components-gallery                            +329 B   (+0.0%)      +56 B   (+0.0%)
async-load-calypso-blocks-inline-help-popover                              -95 B   (-0.0%)      -37 B   (-0.0%)
async-load-signup-steps-import-url-onboarding                              -47 B   (-0.1%)      -15 B   (-0.1%)
async-load-signup-steps-import-url                                         -43 B   (-0.2%)      -16 B   (-0.3%)
async-load-signup-steps-site-picker                                        -42 B   (-0.1%)      -18 B   (-0.1%)
async-load-signup-steps-import-preview                                     -38 B   (-0.1%)      -10 B   (-0.1%)
async-load-signup-steps-clone-destination                                  -38 B   (-0.2%)      -11 B   (-0.2%)
async-load-calypso-layout-nps-survey-notice                                -38 B   (-0.1%)      -11 B   (-0.2%)
async-load-calypso-blocks-support-article-dialog-dialog                    -34 B   (-0.0%)       -7 B   (-0.0%)
async-load-calypso-blocks-legal-updates-banner                             -34 B   (-0.7%)       -8 B   (-0.5%)
async-load-calypso-reader-following-manage                                 -28 B   (-0.0%)       -4 B   (-0.0%)
async-load-calypso-my-sites-current-site-domain-warnings                   -28 B   (-0.0%)       -4 B   (-0.0%)
async-load-calypso-my-sites-guided-transfer                                -24 B   (-0.1%)       -6 B   (-0.1%)
async-load-calypso-reader-list-manage                                      -20 B   (-0.1%)       -3 B   (-0.0%)
async-load-calypso-components-jetpack-sidebar                              -17 B   (-0.1%)       -3 B   (-0.0%)
async-load-signup-steps-site                                               -16 B   (-0.1%)       -7 B   (-0.1%)
async-load-signup-steps-passwordless                                       -16 B   (-0.1%)       -8 B   (-0.1%)
async-load-calypso-extensions-woocommerce-app-store-stats-referrers        -16 B   (-0.0%)       -6 B   (-0.1%)
async-load-calypso-layout-community-translator-launcher                    -13 B   (-0.1%)       -1 B   (-0.0%)
async-load-calypso-components-community-translator                         -13 B   (-0.1%)       -6 B   (-0.2%)
async-load-signup-steps-survey                                             -12 B   (-0.1%)       -3 B   (-0.1%)
async-load-signup-steps-site-type                                          -12 B   (-0.1%)       -3 B   (-0.1%)
async-load-signup-steps-site-or-domain                                     -12 B   (-0.1%)       -2 B   (-0.0%)
async-load-signup-steps-secure-your-brand                                  -12 B   (-0.1%)       -4 B   (-0.1%)
async-load-signup-steps-rewind-were-backing                                -12 B   (-0.1%)       -4 B   (-0.2%)
async-load-signup-steps-rewind-migrate                                     -12 B   (-0.0%)       -6 B   (-0.1%)
async-load-signup-steps-rewind-form-creds                                  -12 B   (-0.0%)       -8 B   (-0.1%)
async-load-signup-steps-reader-landing                                     -12 B   (-0.1%)       -5 B   (-0.2%)
async-load-signup-steps-creds-permission                                   -12 B   (-0.0%)       -4 B   (-0.0%)
async-load-signup-steps-creds-confirm                                      -12 B   (-0.0%)       -4 B   (-0.0%)
async-load-signup-steps-creds-complete                                     -12 B   (-0.1%)       -4 B   (-0.2%)
async-load-signup-steps-clone-start                                        -12 B   (-0.1%)       -4 B   (-0.1%)
async-load-signup-steps-clone-ready                                        -12 B   (-0.0%)       -4 B   (-0.1%)
async-load-signup-steps-clone-jetpack                                      -12 B   (-0.1%)       -4 B   (-0.1%)
async-load-signup-steps-clone-cloning                                      -12 B   (-0.1%)       -4 B   (-0.1%)
async-load-calypso-reader-site-stream                                      -12 B   (-0.0%)       -3 B   (-0.0%)
async-load-calypso-reader-search-stream                                    -12 B   (-0.0%)       -5 B   (-0.0%)
async-load-calypso-reader-feed-stream                                      -12 B   (-0.0%)       -3 B   (-0.0%)
async-load-calypso-my-sites-sidebar-unified                                -12 B   (-0.0%)       -5 B   (-0.0%)
async-load-calypso-my-sites-current-site-notice                            -12 B   (-0.0%)       -6 B   (-0.0%)
async-load-calypso-extensions-woocommerce-app-store-stats                  -12 B   (-0.0%)       -7 B   (-0.0%)
async-load-calypso-blocks-jitm-templates-sidebar-banner                    -12 B   (-0.0%)       -7 B   (-0.1%)
async-load-calypso-blocks-jitm-templates-notice                            -12 B   (-0.0%)       -5 B   (-0.1%)
async-load-calypso-blocks-jitm-templates-default                           -12 B   (-0.0%)       -6 B   (-0.1%)

React components that are loaded lazily, when a certain part of UI is displayed for the first time.

Legend

What is parsed and gzip size?

Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory.
Gzip Size: Compressed size of the JS and CSS files. This much data needs to be downloaded over network.

Generated by performance advisor bot at iscalypsofastyet.com.

@scinos scinos requested review from sirreal and a team November 17, 2020 13:33
@scinos scinos self-assigned this Nov 17, 2020
@scinos
Copy link
Contributor Author

scinos commented Nov 17, 2020

About bundle size: I diffed a few files and the biggest difference come from bundling and using tslib.

Before this PR we bundled node_modules/tslib/tslib.es6.js. This lib is not required for evergreen browsers and it is (kind of) a duplicate of @babel/polyfill.

@@ -25,7 +25,7 @@
},
"scripts": {
"clean": "npx rimraf js css src/__color-studio",
"prepare": "node bin/prepare-sass-assets.js && node bin/build-css.js"
"postinstall": "node bin/prepare-sass-assets.js && node bin/build-css.js"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this change tbh.

Calypso needs those commands before it can use the package, so postinstall seems natural. However any external consumer of @automattic/calypso-color-schemes will also run postinstall, which will fail if they have not installed the dev dependencies of the package.

We could keep prepare and bring back running prepare on Calypso's postinstall, but that means we have to use lerna just to run prepare in a couple of packages.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does yarn workspaces run prepare work to avoid lerna?

It looks like yarn uses different lifecycle scripts, should we be updating these? prepare is a holdover from npm days as far as I can tell…

Copy link
Contributor Author

@scinos scinos Nov 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yarn workspaces run prepare fails if any package in the workspace does not implement a prepare script.

Yarn runs prepare (at least yarn v1), but only for the root package, it doesn't run it for the subpackages (yarnpkg/yarn#3911).

So either we have our own explicit list ("prepare": "yarn workspace @automattic/calypso-color-schemes run prepare && yarn workspace @automattic/languages run prepare"), use a different tool like wsrun or stick with lerna.

{ "path": "../packages/data-stores" },
{ "path": "../packages/language-picker" },
{ "path": "../packages/react-i18n" }
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also a packages/languages package that is written in TypeScript and isn't being migrated in this PR: it's still built during the prepare step.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

packages/languages is migrated in the sense that has calypso:src, but still requires a build step because we do use it to build Calypso: yarn build-languages calls bin/build-languages.js which requires '@automattic/languages'

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, the package is used by a Node.js build script and needs to be built 🙁

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @automattic/languages is in a very similar situation as a Gutenberg webpack plugin we're discussing with @sirreal in WordPress/gutenberg#26382 (comment)

I think we'd be better off if the package was written in plain JavaScript, where it would be a trivial two-liner:

import data from './languages-meta.json';
export default Object.values( data );

and if the types were in a separate index.d.ts file.

Then the package wouldn't need any build step at all, could be directly consumed by Node.js build scripts, and consumers would still get TypeScript types for it without any observable change.

This approach is an exception rather that a rule, but I think it would be justified for certain packages like these I mention.

@sirreal
Copy link
Member

sirreal commented Nov 18, 2020

About bundle size: I diffed a few files and the biggest difference come from bundling and using tslib.

Before this PR we bundled node_modules/tslib/tslib.es6.js. This lib is not required for evergreen browsers and it is (kind of) a duplicate of @babel/polyfill.

This is a nice benefit. Packages are also configured inconsistently so we were likely getting both the bundled tslib and some number of inline or per-module tslib definitions. Ideally all the packages build using tslib.

@@ -7,7 +7,7 @@
"jsx": "react",
"declaration": true,
"declarationDir": "dist/types",
"outDir": "dist/types",
"outDir": "dist/esm",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a fix, esm build was being written to the wrong place 🙂

Copy link
Member

@sirreal sirreal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me and seems to be working as expected. It would be nice to get @Automattic/shilling to do some smoke testing of checkout-related components, but I'm pretty happy if e2e is happy.

Copy link
Member

@jsnajdr jsnajdr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works great for me, too 👍

@mreishus
Copy link
Contributor

Super fast 👍

Copy link
Member

@sirbrillig sirbrillig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problems with checkout that I can detect. And as for the building speed... 😮 I've never seen yarn complete so fast.

Update: I also tested running the branch and modifying a file in a checkout-related package, letting it rebuild, and then making sure the change was included. All worked as expected.

@scinos scinos merged commit 3a6e402 into master Nov 19, 2020
@scinos scinos deleted the add/babel-typescript branch November 19, 2020 04:44
@matticbot matticbot removed the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Nov 19, 2020
@scinos scinos mentioned this pull request Feb 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants