Skip to content

Commit

Permalink
Perf: Improve performance and production with SWC minimization
Browse files Browse the repository at this point in the history
  • Loading branch information
1aron committed Feb 20, 2024
1 parent fd0701c commit df17bfb
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 509 deletions.
3 changes: 1 addition & 2 deletions packages/techor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
"dependencies": {
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-swc": "^0.3.0",
"@swc/core": "^1.3.106",
"@techor/extend": "workspace:^",
"@techor/fs": "workspace:^",
Expand All @@ -78,11 +77,11 @@
"@techor/npm": "workspace:^",
"clsx": "^2.0.0",
"commander": "^11.0.0",
"esbuild": "^0.20.1",
"escodegen": "^2.1.0",
"execa": "^7.2.0",
"explore-config": "workspace:^",
"hrtime": "^0.5.0",
"load-tsconfig": "^0.2.5",
"lodash.isequal": "^4.5.0",
"magic-string": "^0.30.7",
"pkg-types": "^1.0.1",
Expand Down
8 changes: 2 additions & 6 deletions packages/techor/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ import { BuildCommonOptions, Config, default as defaultConfig } from '../config'

// core plugins
import esmShim from '../plugins/esm-shim'
import esbuildTransform from '../plugins/esbuild-transform'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import swc from '@rollup/plugin-swc'
import swc from '../plugins/swc'
import exploreConfig from 'explore-config'

const FORMAT_OF_EXT = {
Expand Down Expand Up @@ -119,9 +118,6 @@ export default (program: Command) => program.command('build [entryPaths...]')
}
}
}
if (config.build.esbuildTransform || outputOptions.minify) {
(outputOptions.output.plugins as RollupOutputOptions['plugins'][]).push(esbuildTransform())
}
let buildOptions = buildMap.get(input)
if (buildOptions) {
// 合併同一個 input 來源並對應多個 RollupOutputOptions 避免重新 parse 相同的 input
Expand All @@ -135,7 +131,7 @@ export default (program: Command) => program.command('build [entryPaths...]')
buildOptions.input.external = (config.build.external && !isGlobalFile) && getWideExternal(config.build.external || []);
(buildOptions.input.plugins as RollupInputPluginOption[]).unshift(
...[
config.build.swc && swc(config.build.swc),
(config.build.swc || outputOptions.minify) && swc({ ...config.build.swc, minify: outputOptions.minify }),
config.build.commonjs && commonjs(config.build.commonjs),
config.build.nodeResolve && nodeResolve(config.build.nodeResolve),
config.build.esmShim && esmShim(),
Expand Down
15 changes: 10 additions & 5 deletions packages/techor/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { InputOptions as RollupInputOptions, OutputOptions as RollupOutputOptions } from 'rollup'
import { TransformOptions as ESBuildTransformOptions } from 'esbuild'
import { Options as SWCOptions } from '@swc/core'
import type { Options as SWCOptions } from './plugins/swc'
import { RollupNodeResolveOptions } from '@rollup/plugin-node-resolve'
import { RollupCommonJSOptions } from '@rollup/plugin-commonjs'

Expand All @@ -22,7 +21,15 @@ const config: Config = {
exportConditions: ['node', 'import', 'require', 'default']
},
commonjs: { extensions: ['.js', '.ts'] },
swc: {},
swc: {
include: /\.[jt]sx?$/,
exclude: ['node_modules'],
jsc: {
target: 'esnext',
keepClassNames: true,
externalHelpers: false
}
},
esmShim: true
}
}
Expand Down Expand Up @@ -53,8 +60,6 @@ export interface BuildOptions extends BuildCommonOptions {
swc?: SWCOptions | false
// https://github.com/rollup/plugins/tree/master/packages/node-resolve#options
nodeResolve?: RollupNodeResolveOptions | false;
// https://esbuild.github.io/api/#transform
esbuildTransform?: ESBuildTransformOptions | false
// We made `techor-esm-shim` because `@rollup/plugin-esm-shim` breaks the source code.
esmShim?: boolean
// https://github.com/rollup/plugins/tree/master/packages/commonjs#options
Expand Down
1 change: 1 addition & 0 deletions packages/techor/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as esmShim } from './plugins/esm-shim'
export { default as esbuildTransform } from './plugins/esbuild-transform'
export { default as swc } from './plugins/swc'
export { default as rawLoader } from './plugins/raw-loader'
export { default as config } from './config'

Expand Down
68 changes: 68 additions & 0 deletions packages/techor/src/plugins/swc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { Plugin } from 'rollup'
// @ts-expect-error Cannot find module 'load-tsconfig' or its corresponding type declarations.ts(2307)
import { loadTsConfig } from 'load-tsconfig'
import { Options as SWCOptions, transform } from '@swc/core'
import extend from '@techor/extend'
import { FilterPattern, createFilter } from '@rollup/pluginutils'

export type Options = SWCOptions & {
include?: FilterPattern
exclude?: FilterPattern
tsconfigFile?: string | boolean
}

export default function swc({ tsconfigFile, include, exclude, minify, ...options }: Options = {}): Plugin {
const filter = createFilter(include, exclude)
const compilerOptions = tsconfigFile === false ? {} : loadTsConfig('.', tsconfigFile === true ? undefined : tsconfigFile)?.data?.compilerOptions || {}
let swcOptions = {
jsc: {
target: compilerOptions.target,
parser: {},
transform: {}
}
} as SWCOptions
if (compilerOptions.experimentalDecorators) {
swcOptions.jsc.parser.decorators = true
swcOptions.jsc.transform.legacyDecorator = true
swcOptions.jsc.transform.decoratorMetadata = compilerOptions.emitDecoratorMetadata
}
if (compilerOptions.jsx) {
swcOptions.jsc.transform.react = {
pragma: compilerOptions.jsxFactory,
pragmaFrag: compilerOptions.jsxFragmentFactory,
importSource: compilerOptions.jsxImportSource,
}
}
swcOptions = extend(swcOptions, options)
return {
name: 'techor-swc',
async transform(code, id) {
if (!filter(id)) return null
const transformed = await transform(code, {
filename: id,
sourceMaps: true,
...extend(swcOptions, {
jsc: {
parser: /\.ts?$/.test(id)
? { syntax: 'typescript', tsx: /\.tsx$/.test(id) }
: { syntax: 'ecmascript', jsx: /\.jsx$/.test(id) }
}
} as SWCOptions)
})
return {
code: transformed.code,
map: transformed.map && JSON.parse(transformed.map),
}
},
async renderChunk(code, chunk) {
return minify
? await transform(code, {
...swcOptions,
sourceMaps: true,
minify: true,
filename: chunk.fileName,
})
: null
}
} as Plugin
}
5 changes: 4 additions & 1 deletion packages/techor/tests/global/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ it('should bundle all deps', () => {
})

it('should be minifined', () => {
expect(readFileSync(join(__dirname, './dist/global.min.js'), 'utf-8')).toBe('(()=>{(function(){"use strict";function c(t){const e=typeof t;return t!==null&&(e==="object"||e==="function")}console.log(c({foo:"bar"})),globalThis.effect1="created";function o(){globalThis.effect2="created"}o()})();})();\n')
expect(readFileSync(join(__dirname, './dist/global.min.js'), 'utf-8')).toBe('(function(){"use strict";function isObject(value){const type=typeof value;return value!==null&&(type==="object"||type==="function")}console.log(isObject({foo:"bar"}));globalThis.effect1="created";function effect2(){globalThis.effect2="created"}effect2()})();\n')
})

it('should not contain @swc/helpers', () => {
expect(readFileSync(join(__dirname, './dist/global.min.js'), 'utf-8')).not.toContain('@swc/helpers')
})
2 changes: 1 addition & 1 deletion packages/techor/tests/minify/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { join } from 'node:path'

test('main', () => {
execSync('tsx ../../src/bin build --minify', { cwd: __dirname })
expect(readFileSync(join(__dirname, './dist/index.mjs'), 'utf-8').toString()).toEqual('function n(){console.log("main")}n();export{n as default};\n')
expect(readFileSync(join(__dirname, './dist/index.mjs'), 'utf-8').toString()).toEqual('function main(){console.log("main")}main();export{main as default};\n')
})
Loading

0 comments on commit df17bfb

Please sign in to comment.