Skip to content

Commit f5739d6

Browse files
authored
fix: reduce MUI size by using @swc/plugin-transform-imports (#169)
* fix: reduce MUI size by using `@swc/plugin-transform-imports` * style: apply ESLint rules to enforce correct import path * fix: fix eslint error message * fix: add rule for `@mui/material/styles` * ci: rewrite MUI import differently for esm and cjs * fix: prevent directory import in ESM build
1 parent 18e9f2a commit f5739d6

File tree

6 files changed

+109
-84
lines changed

6 files changed

+109
-84
lines changed

.eslintrc.js

+9
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ module.exports = {
8888
'@typescript-eslint/no-restricted-imports': [
8989
'error',
9090
{
91+
paths: [
92+
{
93+
name: '@mui/material',
94+
importNames: ['styled', 'createTheme', 'ThemeProvider'],
95+
message: `
96+
Use "import { styled } from '@mui/material/styles'" instead.
97+
Use "import { createTheme, ThemeProvider } from '@mui/material/styles'" instead.`
98+
}
99+
],
91100
patterns: [
92101
{
93102
group: ['**/dist'],

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ tsconfig.tsbuildinfo
1515
.eslintcache
1616
node_modules
1717

18+
.swc
1819
.next
1920
.vercel
2021
coverage

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
"@rollup/plugin-node-resolve": "^15.0.1",
8282
"@rollup/plugin-replace": "^5.0.2",
8383
"@swc/core": "^1.3.27",
84+
"@swc/plugin-transform-imports": "^1.5.36",
8485
"@testing-library/react": "^13.4.0",
8586
"@types/node": "^18.11.18",
8687
"@types/react": "^18.0.27",

rollup.config.ts

+88-80
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,21 @@ import replace from '@rollup/plugin-replace'
88
import type {
99
ModuleFormat,
1010
OutputOptions,
11-
RollupCache,
1211
RollupOptions
1312
} from 'rollup'
1413
import dts from 'rollup-plugin-dts'
1514
import { defineRollupSwcOption, swc } from 'rollup-plugin-swc3'
1615
import { fileURLToPath } from 'url'
1716

18-
let cache: RollupCache
19-
20-
const dtsOutput = new Set<[string, string]>()
21-
2217
const outputDir = fileURLToPath(new URL('dist', import.meta.url))
2318

24-
const external = [
19+
const externalDeps = [
2520
'@emotion/react',
2621
'@emotion/styled',
2722
'@emotion/react/jsx-runtime',
2823
'@emotion/react/jsx-dev-runtime',
2924
'@mui/material',
30-
'@mui/material/styles',
25+
/@mui\/material\/.*/,
3126
'copy-to-clipboard',
3227
'zustand',
3328
'zustand/context',
@@ -37,17 +32,50 @@ const external = [
3732
'react-dom',
3833
'react-dom/client'
3934
]
35+
36+
const aliasPlugin = alias({
37+
entries: [
38+
{ find: 'react', replacement: '@emotion/react' },
39+
{ find: 'react/jsx-runtime', replacement: '@emotion/react/jsx-runtime' },
40+
{ find: 'react/jsx-dev-runtime', replacement: '@emotion/react/jsx-dev-runtime' }
41+
]
42+
})
43+
44+
const replacePlugin = replace({
45+
preventAssignment: true,
46+
'process.env.NODE_ENV': JSON.stringify('production'),
47+
'typeof window': JSON.stringify('object')
48+
})
49+
50+
const esmTransformImportsPlugin: [string, Record<string, any>] = [
51+
'@swc/plugin-transform-imports',
52+
{
53+
'@mui/material': { transform: '@mui/material/{{member}}/index.js' },
54+
'@mui/material/styles': { transform: '@mui/material/styles/{{member}}.js' }
55+
}
56+
]
57+
58+
const cjsTransformImportsPlugin: [string, Record<string, any>] = [
59+
'@swc/plugin-transform-imports',
60+
{
61+
'@mui/material': { transform: '@mui/material/node/{{member}}' },
62+
'@mui/material/styles': { transform: '@mui/material/node/styles/{{member}}' }
63+
}
64+
]
65+
4066
const outputMatrix = (
4167
name: string, format: ModuleFormat[]): OutputOptions[] => {
4268
const baseName = basename(name)
43-
return format.flatMap(format => ({
69+
return format.map(format => ({
4470
file: resolve(outputDir, `${baseName}.${format === 'es' ? 'm' : ''}js`),
4571
sourcemap: false,
4672
name: 'JsonViewer',
4773
format,
4874
banner: `/// <reference types="./${baseName}.d.ts" />`,
49-
globals: external.reduce((object, module) => {
50-
object[module] = module
75+
globals: externalDeps.reduce((object, module) => {
76+
if (typeof module === 'string') {
77+
object[module] = module
78+
}
5179
return object
5280
}, {} as Record<string, string>)
5381
}))
@@ -56,84 +84,64 @@ const outputMatrix = (
5684
const buildMatrix = (input: string, output: string, config: {
5785
format: ModuleFormat[]
5886
browser: boolean
59-
dts: boolean
60-
}): RollupOptions => {
61-
if (config.dts) {
62-
dtsOutput.add([input, output])
63-
}
64-
return {
65-
input,
66-
output: outputMatrix(output, config.format),
67-
cache,
68-
external: config.browser ? [] : external,
69-
plugins: [
70-
alias({
71-
entries: config.browser
72-
? []
73-
: [
74-
{ find: 'react', replacement: '@emotion/react' },
75-
{
76-
find: 'react/jsx-dev-runtime',
77-
replacement: '@emotion/react/jsx-dev-runtime'
78-
},
79-
{
80-
find: 'react/jsx-runtime',
81-
replacement: '@emotion/react/jsx-runtime'
87+
}): RollupOptions[] => {
88+
return [
89+
...config.format.map(format => ({
90+
input,
91+
output: outputMatrix(output, [format]),
92+
external: config.browser ? [] : externalDeps,
93+
94+
plugins: [
95+
!config.browser && aliasPlugin,
96+
config.browser && replacePlugin,
97+
commonjs(),
98+
nodeResolve(),
99+
swc(defineRollupSwcOption({
100+
jsc: {
101+
externalHelpers: true,
102+
parser: {
103+
syntax: 'typescript',
104+
tsx: true
105+
},
106+
transform: {
107+
react: {
108+
runtime: 'automatic',
109+
importSource: '@emotion/react'
82110
}
83-
]
84-
}),
85-
config.browser && replace({
86-
preventAssignment: true,
87-
'process.env.NODE_ENV': JSON.stringify('production'),
88-
'typeof window': JSON.stringify('object')
89-
}),
90-
commonjs(),
91-
nodeResolve(),
92-
swc(defineRollupSwcOption({
93-
jsc: {
94-
externalHelpers: true,
95-
parser: {
96-
syntax: 'typescript',
97-
tsx: true
98-
},
99-
transform: {
100-
react: {
101-
runtime: 'automatic',
102-
importSource: '@emotion/react'
111+
},
112+
experimental: {
113+
plugins: config.browser
114+
? []
115+
: format === 'es'
116+
? [esmTransformImportsPlugin]
117+
: [cjsTransformImportsPlugin]
103118
}
104119
}
105-
}
106-
}))
107-
]
108-
}
109-
}
110-
111-
const dtsMatrix = (): RollupOptions[] => {
112-
return [...dtsOutput.values()].flatMap(([input, output]) => ({
113-
input,
114-
cache,
115-
output: {
116-
file: resolve(outputDir, `${output}.d.ts`),
117-
format: 'es'
118-
},
119-
plugins: [
120-
dts()
121-
]
122-
}))
120+
}))
121+
]
122+
})),
123+
{
124+
input,
125+
output: {
126+
file: resolve(outputDir, `${output}.d.ts`),
127+
format: 'es'
128+
},
129+
plugins: [
130+
dts()
131+
]
132+
}
133+
]
123134
}
124135

125136
const build: RollupOptions[] = [
126-
buildMatrix('./src/index.tsx', 'index', {
127-
format: ['es', 'umd'],
128-
browser: false,
129-
dts: true
137+
...buildMatrix('./src/index.tsx', 'index', {
138+
format: ['es', 'cjs'],
139+
browser: false
130140
}),
131-
buildMatrix('./src/browser.tsx', 'browser', {
141+
...buildMatrix('./src/browser.tsx', 'browser', {
132142
format: ['es', 'umd'],
133-
browser: true,
134-
dts: true
135-
}),
136-
...dtsMatrix()
143+
browser: true
144+
})
137145
]
138146

139147
export default build

src/index.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import {
2-
createTheme, Paper,
3-
ThemeProvider
4-
} from '@mui/material'
1+
import { Paper } from '@mui/material'
2+
import { createTheme, ThemeProvider } from '@mui/material/styles'
53
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
64

75
import { DataKeyPair } from './components/DataKeyPair'

yarn.lock

+8
Original file line numberDiff line numberDiff line change
@@ -1721,6 +1721,13 @@ __metadata:
17211721
languageName: node
17221722
linkType: hard
17231723

1724+
"@swc/plugin-transform-imports@npm:^1.5.36":
1725+
version: 1.5.36
1726+
resolution: "@swc/plugin-transform-imports@npm:1.5.36"
1727+
checksum: b47cbb9bdd29d20ac391050ac19afe862cc3bd86c17de5405789ff2e815e710d4ad2ab3356427c73a0b6da11f8757f707171cbd2ad325970f29af525dfb654e2
1728+
languageName: node
1729+
linkType: hard
1730+
17241731
"@testing-library/dom@npm:^8.5.0":
17251732
version: 8.18.1
17261733
resolution: "@testing-library/dom@npm:8.18.1"
@@ -1784,6 +1791,7 @@ __metadata:
17841791
"@rollup/plugin-node-resolve": ^15.0.1
17851792
"@rollup/plugin-replace": ^5.0.2
17861793
"@swc/core": ^1.3.27
1794+
"@swc/plugin-transform-imports": ^1.5.36
17871795
"@testing-library/react": ^13.4.0
17881796
"@types/node": ^18.11.18
17891797
"@types/react": ^18.0.27

0 commit comments

Comments
 (0)