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

Add experimental SWC minify and SWC loader options #27664

Merged
merged 10 commits into from
Aug 6, 2021

Conversation

timneutkens
Copy link
Member

@timneutkens timneutkens commented Aug 1, 2021

Adds 2 experimental options:

module.exports = {
  experimental: {
    // Replaces Babel (transforms ran against first-party code) with next-swc
    swcLoader: true,
    // Replaces Terser (minifier) with next-swc
    swcMinify: true,
  } 
}

Both features are still work in progress. In particular there are currently a few caveats to know about:

  • Publishing of native binaries has not been added yet, these options can only be used on the Next.js repository right now
  • swcLoader
    • Custom Babel configuration is not supported
    • Next.js Babel plugins being ported to SWC (in progress):
      • next-ssg - tree shaking of getStaticProps, getStaticPaths, and getServerSideProps
      • next-dynamic - Adds metadata for next/dynamic to function correctly between server/browser
      • amp-attributes plugin - transform className to class on AMP tags
      • styled-jsx - support for <style jsx>. Until this is ported you can't use <style jsx>.
      • next-page-disallow-re-export-all-exports - transform that prevents common pitfall where tree shaking does not work, this is not a blocker for usage of swcLoader
      • next-page-config - transform that ensures export const config in pages is a static object that can be extracted, this is not a blocker for usage of swcLoader
  • swcMinify
    • Minification is not on par with Terser output yet, see below results (in progress)
Size comparison between no minification <-> SWC minify <-> Terser

No minification

Page                                            Size     First Load JS
  /404                                        329 B          97.6 kB
  /about                                      517 B          97.8 kB
  /development-logs                           3.32 kB         101 kB
  /development-logs/link-with-no-prefetch     3.33 kB         101 kB
  /development-logs/link-with-prefetch-false  3.34 kB         101 kB
  /dynamic                                    3.29 kB         101 kB
  /dynamic/chunkfilename                      4.31 kB         102 kB
  /dynamic/function                           4.29 kB         102 kB
  /dynamic/head                               4.94 kB         102 kB
  /dynamic/multiple-modules                   4.42 kB         102 kB
  /dynamic/nested                             4.3 kB          102 kB
  /dynamic/no-chunk                           5.99 kB         103 kB
  /dynamic/no-ssr                             4.3 kB          102 kB
  /dynamic/no-ssr-custom-loading              4.36 kB         102 kB
  /dynamic/ssr                                4.29 kB         102 kB
  /dynamic/ssr-true                           4.3 kB          102 kB
  /hmr                                        3.3 kB          101 kB
  /hmr/about                                  545 B          97.8 kB
  /hmr/about1                                 544 B          97.8 kB
  /hmr/about2                                 545 B          97.8 kB
  /hmr/about3                                 544 B          97.8 kB
  /hmr/about4                                 545 B          97.8 kB
  /hmr/about5                                 543 B          97.8 kB
  /hmr/about6                                 545 B          97.8 kB
  /hmr/about7                                 546 B          97.8 kB
  /hmr/contact                                545 B          97.8 kB
  /hmr/counter                                2.34 kB        99.6 kB
 λ /hmr/error-in-gip                           2.06 kB        99.3 kB
  /hmr/style                                  659 B           104 kB
  /hmr/style-dynamic-component                4.36 kB         102 kB
  /hmr/style-stateful-component               2.16 kB         106 kB
  /process-env                                513 B          97.8 kB
+ First Load JS shared by all                   97.3 kB
   chunks/framework.054ead.js                  43.7 kB
   chunks/main.2953d6.js                       48.4 kB
   chunks/pages/_app.b4bcb0.js                 1.72 kB
   chunks/webpack.eb940a.js                    3.39 kB

SWC Minify

Page                                            Size     First Load JS
  /404                                        261 B          83.2 kB
  /about                                      396 B          83.3 kB
  /development-logs                           2.4 kB         85.3 kB
  /development-logs/link-with-no-prefetch     2.4 kB         85.3 kB
  /development-logs/link-with-prefetch-false  2.41 kB        85.3 kB
  /dynamic                                    2.37 kB        85.3 kB
  /dynamic/chunkfilename                      3.44 kB        86.3 kB
  /dynamic/function                           3.43 kB        86.3 kB
  /dynamic/head                               3.99 kB        86.9 kB
  /dynamic/multiple-modules                   3.52 kB        86.4 kB
  /dynamic/nested                             3.43 kB        86.3 kB
  /dynamic/no-chunk                           4.99 kB        87.9 kB
  /dynamic/no-ssr                             3.43 kB        86.3 kB
  /dynamic/no-ssr-custom-loading              3.49 kB        86.4 kB
  /dynamic/ssr                                3.42 kB        86.3 kB
  /dynamic/ssr-true                           3.43 kB        86.3 kB
  /hmr                                        2.37 kB        85.3 kB
  /hmr/about                                  421 B          83.3 kB
  /hmr/about1                                 420 B          83.3 kB
  /hmr/about2                                 421 B          83.3 kB
  /hmr/about3                                 420 B          83.3 kB
  /hmr/about4                                 421 B          83.3 kB
  /hmr/about5                                 420 B          83.3 kB
  /hmr/about6                                 421 B          83.3 kB
  /hmr/about7                                 421 B          83.3 kB
  /hmr/contact                                420 B          83.3 kB
  /hmr/counter                                2.12 kB          85 kB
 λ /hmr/error-in-gip                           1.86 kB        84.7 kB
  /hmr/style                                  522 B          87.9 kB
  /hmr/style-dynamic-component                3.48 kB        86.4 kB
  /hmr/style-stateful-component               1.95 kB        89.4 kB
  /process-env                                391 B          83.3 kB
+ First Load JS shared by all                   82.9 kB
   chunks/framework.538315.js                  45.4 kB
   chunks/main.92cc87.js                       33.8 kB
   chunks/pages/_app.8bbecc.js                 1.39 kB
   chunks/webpack.4302ce.js                    2.29 kB

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
  (Static)  automatically rendered as static HTML (uses no initial props)
  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)
   (ISR)     incremental static regeneration (uses revalidate in getStaticProps)

Terser (current Next.js default)

Page                                            Size     First Load JS
  /404                                        195 B          67.9 kB
  /about                                      277 B            68 kB
  /development-logs                           1.66 kB        69.4 kB
  /development-logs/link-with-no-prefetch     1.66 kB        69.4 kB
  /development-logs/link-with-prefetch-false  1.68 kB        69.4 kB
  /dynamic                                    1.63 kB        69.3 kB
  /dynamic/chunkfilename                      2.47 kB        70.2 kB
  /dynamic/function                           2.45 kB        70.2 kB
  /dynamic/head                               2.81 kB        70.5 kB
  /dynamic/multiple-modules                   2.52 kB        70.2 kB
  /dynamic/nested                             2.45 kB        70.2 kB
  /dynamic/no-chunk                           3.35 kB        71.1 kB
  /dynamic/no-ssr                             2.46 kB        70.2 kB
  /dynamic/no-ssr-custom-loading              2.5 kB         70.2 kB
  /dynamic/ssr                                2.46 kB        70.2 kB
  /dynamic/ssr-true                           2.46 kB        70.2 kB
  /hmr                                        1.64 kB        69.4 kB
  /hmr/about                                  298 B            68 kB
  /hmr/about1                                 297 B            68 kB
  /hmr/about2                                 298 B            68 kB
  /hmr/about3                                 297 B            68 kB
  /hmr/about4                                 299 B            68 kB
  /hmr/about5                                 297 B            68 kB
  /hmr/about6                                 299 B            68 kB
  /hmr/about7                                 299 B            68 kB
  /hmr/contact                                298 B            68 kB
  /hmr/counter                                1.27 kB          69 kB
 λ /hmr/error-in-gip                           1.11 kB        68.8 kB
  /hmr/style                                  371 B          71.6 kB
  /hmr/style-dynamic-component                2.48 kB        70.2 kB
  /hmr/style-stateful-component               1.19 kB        72.4 kB
  /process-env                                268 B            68 kB
+ First Load JS shared by all                   67.7 kB
   chunks/framework.d403d4.js                  42.2 kB
   chunks/main.946cb8.js                       22.8 kB
   chunks/pages/_app.ddf6f3.js                 980 B
   chunks/webpack.8df494.js                    1.73 kB

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
  (Static)  automatically rendered as static HTML (uses no initial props)
  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)
   (ISR)     incremental static regeneration (uses revalidate in getStaticProps)

This is an experimental option to quickly test the new SWC minifier which is still being worked on.
@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@ijjk
Copy link
Member

ijjk commented Aug 6, 2021

Failing test suites

Commit: af2fdda

test/acceptance/ReactRefreshLogBox.dev.test.js

  • server-side only compilation errors

Expand output

● server-side only compilation errors

ScriptTimeoutError: script timeout
  (Session info: headless chrome=92.0.4515.131)

  72 |
  73 |             // Wait for application to re-hydrate:
> 74 |             await browser.executeAsyncScript(function () {
     |             ^
  75 |               var callback = arguments[arguments.length - 1]
  76 |               if (window.__NEXT_HYDRATED) {
  77 |                 callback()

  at Object.throwDecodedError (../node_modules/selenium-webdriver/lib/error.js:550:15)
  at parseHttpResponse (../node_modules/selenium-webdriver/lib/http.js:565:13)
  at Executor.execute (../node_modules/selenium-webdriver/lib/http.js:491:26)
      at runMicrotasks (<anonymous>)
  at Proxy.execute (../node_modules/selenium-webdriver/lib/webdriver.js:700:17)
  at Object.patch (acceptance/helpers.js:74:13)
  at Object.<anonymous> (acceptance/ReactRefreshLogBox.dev.test.js:1415:3)

Refactored the loader to match up with the `next/babel` defaults. Also added tracing to measure performance.
@ijjk

This comment has been minimized.

swc_atoms = "0.2.6"
swc_common = { version = "0.11.1", features = ["tty-emitter", "sourcemap"] }
swc_node_base = "0.2.0"
swc_ecmascript = { version = "0.48.0", features = ["codegen", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] }
swc_ecmascript = { version = "0.50.0", features = ["codegen", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] }
Copy link
Member

Choose a reason for hiding this comment

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

I think swc_ecmascript should reexport swc_ecma_preset_env.
I'll do it soon.

yarn.lock Show resolved Hide resolved
@ijjk
Copy link
Member

ijjk commented Aug 6, 2021

Stats from current PR

Default Build (Decrease detected ✓)
General Overall increase ⚠️
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
buildDuration 14.9s 15.5s ⚠️ +586ms
buildDurationCached 3.7s 3.5s -157ms
nodeModulesSize 50.2 MB 50.2 MB ⚠️ +2.26 kB
Page Load Tests Overall decrease ⚠️
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
/ failed reqs 0 0
/ total time (seconds) 2.654 2.611 -0.04
/ avg req/sec 941.95 957.46 +15.51
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.454 1.479 ⚠️ +0.03
/error-in-render avg req/sec 1719.58 1690.47 ⚠️ -29.11
Client Bundles (main, webpack, commons)
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
745.HASH.js gzip 179 B 179 B
framework-HASH.js gzip 42.2 kB 42.2 kB
main-HASH.js gzip 23.1 kB 23.1 kB
webpack-HASH.js gzip 1.5 kB 1.5 kB
Overall change 67 kB 67 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
polyfills-HASH.js gzip 31.1 kB 31.1 kB
Overall change 31.1 kB 31.1 kB
Client Pages
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
_app-HASH.js gzip 980 B 980 B
_error-HASH.js gzip 194 B 194 B
amp-HASH.js gzip 312 B 312 B
css-HASH.js gzip 329 B 329 B
dynamic-HASH.js gzip 2.52 kB 2.52 kB
head-HASH.js gzip 350 B 350 B
hooks-HASH.js gzip 904 B 904 B
image-HASH.js gzip 4.12 kB 4.12 kB
index-HASH.js gzip 261 B 261 B
link-HASH.js gzip 1.66 kB 1.66 kB
routerDirect..HASH.js gzip 319 B 319 B
script-HASH.js gzip 387 B 387 B
withRouter-HASH.js gzip 320 B 320 B
bb14e60e810b..30f.css gzip 125 B 125 B
Overall change 12.8 kB 12.8 kB
Client Build Manifests
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
_buildManifest.js gzip 490 B 490 B
Overall change 490 B 490 B
Rendered Page Sizes
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
index.html gzip 531 B 531 B
link.html gzip 542 B 542 B
withRouter.html gzip 523 B 523 B
Overall change 1.6 kB 1.6 kB

Webpack 4 Mode (Decrease detected ✓)
General Overall increase ⚠️
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
buildDuration 12.1s 12.3s ⚠️ +211ms
buildDurationCached 4.8s 4.7s -85ms
nodeModulesSize 50.2 MB 50.2 MB ⚠️ +2.26 kB
Page Load Tests Overall decrease ⚠️
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
/ failed reqs 0 0
/ total time (seconds) 2.642 2.645 0
/ avg req/sec 946.33 945.28 ⚠️ -1.05
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.468 1.504 ⚠️ +0.04
/error-in-render avg req/sec 1703.1 1661.79 ⚠️ -41.31
Client Bundles (main, webpack, commons)
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
17.HASH.js gzip 185 B 185 B
677f882d2ed8..HASH.js gzip 14 kB 14 kB
framework.HASH.js gzip 41.9 kB 41.9 kB
main-HASH.js gzip 10.6 kB 10.6 kB
webpack-HASH.js gzip 1.19 kB 1.19 kB
Overall change 67.8 kB 67.8 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
polyfills-HASH.js gzip 31.3 kB 31.3 kB
Overall change 31.3 kB 31.3 kB
Client Pages
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
_app-HASH.js gzip 965 B 965 B
_error-HASH.js gzip 3.71 kB 3.71 kB
amp-HASH.js gzip 552 B 552 B
css-HASH.js gzip 333 B 333 B
dynamic-HASH.js gzip 2.71 kB 2.71 kB
head-HASH.js gzip 2.97 kB 2.97 kB
hooks-HASH.js gzip 911 B 911 B
index-HASH.js gzip 231 B 231 B
link-HASH.js gzip 1.64 kB 1.64 kB
routerDirect..HASH.js gzip 298 B 298 B
script-HASH.js gzip 2.94 kB 2.94 kB
withRouter-HASH.js gzip 294 B 294 B
e025d2764813..52f.css gzip 125 B 125 B
Overall change 17.7 kB 17.7 kB
Client Build Manifests
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
_buildManifest.js gzip 498 B 498 B
Overall change 498 B 498 B
Rendered Page Sizes
vercel/next.js canary timneutkens/next.js add/experimental-swc-minify Change
index.html gzip 576 B 576 B
link.html gzip 589 B 589 B
withRouter.html gzip 570 B 570 B
Overall change 1.74 kB 1.74 kB
Commit: 938417a

@timneutkens timneutkens changed the title Add experimental SWC minify option Add experimental SWC minify and SWC loader options Aug 6, 2021
@timneutkens timneutkens merged commit d2f43b7 into vercel:canary Aug 6, 2021
@timneutkens timneutkens deleted the add/experimental-swc-minify branch August 6, 2021 14:07
@wongmjane
Copy link
Contributor

Awesome work on perf! I noticed the caveat of using SWC Loader leading to custom Babel configuration not being supported. I wonder if that will change. Thanks!

In particular there are currently a few caveats to know about:

  • swcLoader
    • Custom Babel configuration is not supported

flybayer pushed a commit to blitz-js/next.js that referenced this pull request Aug 19, 2021
@vercel vercel locked as resolved and limited conversation to collaborators Jan 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants