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

[Spike]: Replacing Babel with SWC in Webpack5-based Projects #24467

Closed
24 tasks
valentinpalkovic opened this issue Oct 13, 2023 · 0 comments
Closed
24 tasks

[Spike]: Replacing Babel with SWC in Webpack5-based Projects #24467

valentinpalkovic opened this issue Oct 13, 2023 · 0 comments
Assignees
Labels

Comments

@valentinpalkovic
Copy link
Contributor

valentinpalkovic commented Oct 13, 2023

Objective: Determine the feasibility and implications of replacing the default Babel builder with SWC in Webpack5-based projects, especially in the context of the Storybook.

1. Investigate hurdles to remove the babel-loader and replace it with swc-loader

Results:

babel-plugin-react-docgen

In Storybook 8.0, we want to use react-docgen as the default tool to extract type information for the controls panel. Currently, it is operated via a babel plugin called babel-plugin-react-docgen.

Task: Replace the babel plugin by an appropriate webpack-loader, which calls react-docgen. Similar was done for the vite-builder.

storybookjs/babel-plugin-named-exports-order

This plugin is necessary to persist the correct export order of Stories, since webpack and vite sometimes doesn't preserve the original order.

Task: This plugin has to be rewritten as a webpack-loader. Similar was done for the vite builder.

react-refresh/babel

The react-refresh/babel plugin is necessary to make fast refresh work for React-based projects. It works together with the webpack plugin https://github.com/pmmmwh/react-refresh-webpack-plugin

Task: A specific SWC setting has to be passed to the swc-loader to enable fast-refresh for react-based projects only: https://swc.rs/docs/configuration/compilation#jsctransformreactrefresh

No flow support

SWC does not have flow support. People would have to opt-out from swc and use babel instead, if they would like to continue to use flow.

2. List all frameworks which are not able to use SWC or in a limited way

Frameworks

Angular

Switching to SWC does not make much sense since Angular plans to continue with esbuild instead of SWC as a compiler. The Angular esbuild builder is still experimental though and we don't know yet how to easily integrate it. We are collaborating with the Angular team to achieve some esbuild support sooner or later. For now, we cannot ditch babel support since SWC still needs to support Angular.

Next.js

We have some custom babel plugins in place, which are necessary for Next.js. We cannot rewrite them to SWC plugins, since the Node binding of SWC doesn't have a Javascript Plugin API. Plugins have to be translated into Rust and then compiled together with SWC, which then could be used via WASM in Node.js. An alternative would be to try out whether we could use the Next.js' custom Rust compiler, which builds on top of SWC or to use Next.js' next-custom-loader, which configures swc under the hood. I have tried out this approach. The main issue is, that, for example, the font webpack plugins have to be rewritten since Next.js' implementation of how fonts are loaded differs from the current implementation in Storybook with Babel. I can't say how complex and long it takes to fully support SWC.

[UPDATE] Next.js findings

After some experimentation, it was possible to use Next.js' next-swc-loader in @storybook/nextjs. This also made it possible to support @next/font without the need of creating custom Babel files like it is needed in Storybook 7.
It can be experimented with the following canary version: 0.0.0-pr-24504-sha-5d9e47a4.

Unfortunately, because next-swc-loader uses internal profiling utilities which are not available in Storybook's implementation, we needed to create a local patch of the next-swc-loader to remove the profiling, and thus make the loader work correctly. Some small changes are needed to support both Babel and SWC, but it's very feasible.

Ember

Ember sets up some babel plugins: (babel-plugin-ember-modules-api-polyfill and babel-plugin-htmlbars-inline-precompile). Not sure, whether it works with SWC out of the box.

Preact

Preact has a plugin to support fast refresh. Hooks, though, require a special babel plugin. This isn't available for SWC. Therefore, full support for fast refresh is not possible.

Satellites depending on babel

Sandbox compatibility

Sandbox Startup HMR + Fast Refresh Docs Play Function
cra-default-js   ✅
cra-default-ts   ✅
react-webpack-17-ts   ✅
react-webpack-18-ts   ✅
nextjs-default-ts   ✅
html-webpack   ✅ HMR
preact   ✅ HMR

Questions

  • What are the implications of relying on SWC and removing Babel from Storybook 8?

    • Babel is still pretty much relevant (over 44 million weekly downloads on npm). Once Babel 8 is released, if there are substantial changes or anything breaks in Storybook projects, we will not detect this and thus will rely on users to report back. We will have to act upon providing fixes, or just delegate this to users, but this will likely result in frustration.
    • Users will have to set up Babel themselves in their project. Maybe this can be automated via automigration or codemod, but only to an extend, as user's projects can vary in complexity.
    • Storybook 7 relies on certain babel configuration such as babel-plugin-named-exports-order and caching setup. In Storybook 8, assuming all the Babel configs are removed, users who migrate from Storybook 7 to Storybook 8 would need to know about these inner workings and set them up themselves.
    • Users who opt out of SWC will still have SWC in the bundle, with an additional 35mb in size, even if not used.
  • What about the coverage addon, which relies on Babel?

  • Should we bootstrap new Webpack5-based Storybook inits with SWC per default in 7.x already?

Proposals

Proposal 1: Storybook 8 does not provide any Babel support

PR: #24504

In Storybook 8.0, the webpack5 builder is configured per default with swc. The babel-loader is not set up; hence, users must manually set up the babel integration. The swc-loader will be set up per default to provide a zero-config experience for users, which setup Storybook in new projects

Tasks

Remove babel-loader and its dependencies

  • The webpack5 builder doesn't implement babel anymore. Therefore we can remove babel as a peer dependency in all packages where possible.
  • The babel and babelDefault presets can be removed. export const babel = ... and export const babelDefault = ... statements doesn't have any effects in preset files anymore.
  • The Typescript preset setting skipBabel is not handled anymore and should be removed in all places.
  • Remove the automigration which adds a missing babel rc file
  • During sandbox generation, don't install a default list of babel presets and plugins automatically for webpack-based projects
  • Docs: Remove documentation about how to use custom babel configuration via presets
  • Remove the internal/swc-webpack sandbox, since we have sandboxes, which cover swc as a compiler
  • Set up babel-loader for frameworks which don't support SWC
    • Ember

A list of babel plugins, which were applied per default:

  • react-refresh/babel
  • storybook-react-refresh
  • @babel/preset-react
  • babel-plugin-add-react-displayname

Add SWC compiler as default compiler for Webpack5

  • Set up SWC-loader per default for webpack5
  • Add required custom SWC configuration for specific frameworks/renderers
    • React Renderer (Set up fast refresh)
    • Next.js: Skip custom swc-loader and use the next-swc-loader, which uses a custom build of swc with plugins integrated)
  • Add documentation to opt-out from swc and to use a custom babel setup instead
  • (Optional): Add codemod to remove or at least warn about storybook-addon-swc addon if in use

Advantages

  • Out-of-the-box compiler in place (SWC)

Disadvantages

  • swc and swc-loader as dependencies are always shipped, even if it is not needed (CRA, Next.js, Angular)
  • some frameworks/renderers have some complex babel configs in place. We leave it up to the user to reconfigure things to make them work.

Proposal 2: Storybook 8 is compiler agnostic for the Webpack5 builder

PR: #24598

In Storybook 8, the Webpack5 builder is not set up with a default compiler. Instead, Storybook or the community will provide addons to configure a compiler for Storybook. Since the default experience should still work out of the box, Storybook will provide a @storybook/addon-webpack5-compiler-swc package, which sets up the swc-loader. All newly generated webpack5-based sandboxes, which are SWC capable, will be set up with this addon configured.

To guarantee a smooth migration, we will also provide a @storybook/addon-webpack5-compiler-babel7 package, which configures the babel-loader and the necessary setup for projects that cannot or don't want to migrate away from a babel setup.

Questions:

How should we handle breaking changes between major versions of Babel?
There are two possibilities: Either we release a new addon like @storybook/addon-webpack5-compiler-babel8 to encapsulate Babel 8-related logic, or we move the addon outside of the mono repo to be able to use its versioning. It could follow semver-versioning and wouldn't be coupled to the breaking change version cycle of the mono repository.

Tasks

  • All tasks from Proposal 1, except setting up SWC
  • Create a @storybook/addon-webpack5-compiler-swc package
    • Register swc-loader via webpackFinal in preset.ts
    • Adjust sandboxes to add the addon for all webpack5 sandboxes, which are capable of using SWC
  • Create a @storybook/addon-webpack5-compiler-babel7 package
    • Register babel-loader via webpackFinal in preset.ts
    • Configure it for all supported frameworks/renderers
  • Write an auto migration to add @storybook/addon-webpack5-compiler-babel7 for all Webpack5-based projects
  • Add documentation to setup a compiler for Webpack5

Spike Results

Sandbox Default Compiler Description
Angular X The angular framework doesn't need any compiler addon because we load their webpack config, which already has the babel-loader set up.
HTML-WEBPACK5 SWC
PREACT-WEBPACK5 SWC A documentation might be necessary for users who might stick with babel to make sure that a .babelrc file exists and that "@babel/plugin-transform-react-jsx is set up properly, because Storybook wouldn't apply any default configuration anymore
CRA JS/TS X Should not use SWC since it uses babel already under the hood.
Next.js X Does initialize its very own next-swc-loader to setup swc. If the user wants to opt-out for Babel, custom babel configuration remain in place and @storybook/addon-webpack5-compiler-babel7 must be used.

Advantages

  • builder-webpack5 is lightweight since it doesn't ship any default compiler
  • separation of concerns: We strictly separate the Webpack5 builder and compilers. Also, updating compilers can happen in the same addon package or a new one if it turns out that covering multiple babel versions in one addon is impossible.

Disadvantages

  • We introduce two new dependencies
@valentinpalkovic valentinpalkovic self-assigned this Oct 13, 2023
@valentinpalkovic valentinpalkovic changed the title [Bug]: [Spike]: Replacing Babel with SWC in Webpack5-based Projects Oct 13, 2023
@vanessayuenn vanessayuenn moved this to Project Tracking Issue in Core Team Projects Oct 23, 2023
@github-project-automation github-project-automation bot moved this from Project Tracking Issue to Done in Core Team Projects Nov 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Archived in project
Development

No branches or pull requests

3 participants
@valentinpalkovic @vanessayuenn and others