Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
バンドル最適化マニアクス at tfconf
Search
Koutarou Chikuba
May 14, 2022
Programming
4.7k
8
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
バンドル最適化マニアクス at tfconf
treeshake, DCE, terser mangling
Koutarou Chikuba
May 14, 2022
More Decks by Koutarou Chikuba
See All by Koutarou Chikuba
技術記事、 専門家としてのプログラマ、 言語化
mizchi
14
8.1k
CI/CD 改善の勘所
mizchi
0
250
極限環境で最終ビルドを絞るためのフロントエンド設計
mizchi
16
6.2k
Server Side JavaScript のためのバンドル最適化
mizchi
5
8k
V8 as a container on CDN Edge worker
mizchi
6
2.6k
Edge Side Frontend という新領域
mizchi
35
14k
「たかがJavaScript」のその先 #TECHPLAY
mizchi
47
21k
Deno Node 両刀
mizchi
7
2.7k
「フロントエンド領域」を再定義する
mizchi
50
38k
Other Decks in Programming
See All in Programming
React本体のコードリーディング
high_g_engineer
1
160
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
4
1.8k
リアルな遅延を測る仕様
kota_yata
1
130
レビュー履歴をAIに食わせて、 Compose移行を加速するs
shihochan
0
210
片田舎のおっさん、 Swift Buildのダイアモンド問題解決の不具合修正PRを出すが、解決方法がキャッシュをしないようにすることであり、ビルド時間が伸びると言われてマージされないので高速化もする/swiftbuild
yimajo
0
280
AIに既存システムを理解させる技術 ~レガシーを見捨てないハーネスエンジニアリング入門~
ochtum
0
150
楽しそうなつよつよエンジニアと目が死んでる僕/A brilliant engineer having a blast, and dead-eyed me.
3l4l5
2
240
コンパウンドプロダクト開発のためのローカルプロセスマネージャー再発明 #layerxgo
izumin5210
0
340
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
230
バグを直したら useEffect が消えた
colorful12
3
700
【QA Test Talk Vol.8】AI-DLC による Whole Team Approach の加速
pkshadeck
PRO
0
240
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
19k
Featured
See All Featured
How to Talk to Developers About Accessibility
jct
2
520
How to build a perfect <img>
jonoalderson
1
5.9k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
430
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
480
Fireside Chat
paigeccino
42
4k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Scaling GitHub
holman
464
140k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Chasing Engaging Ingredients in Design
codingconduct
0
280
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.9k
Transcript
όϯυϧ࠷దԽϚχΞΫε @mizchi | Plaid, Inc at Techfeed Conference 2022
JS Ͱ͔͍ͬͱਏ͘ͳ͍ʁ
JS Ͱ͔͍ͬͱ͖… » ։ൃ࣌ » खݩͷϏϧυαΠΫϧ͕͍ » npm install Ͱ
CI ͕͍ » Ϣʔβʔମݧ » μϯϩʔυͰىಈ·Ͱ͕ͯ͘ਏ͍ » CPU ࠅͰόοςϦ͕ਏ͍
ϑϩϯτΤϯυվળ㲈Ϗϧυվળ
୭͕ԿΛվળ͢Δͷ͔ʁ » ΞϓϦέʔγϣϯ։ൃऀ: ϚΫϩνϡʔχϯά » Chunk Split / Treeshake »
ϥΠϒϥϦ։ൃऀ: ϚΠΫϩνϡʔχϯά » Treeshakable ͳ API ͷఏڙ » mangling
ࠓ͢༰ » جૅฤ: օ͕Δ͖ Treeshake+DCE » ্ڃฤ: ϥΠϒϥϦ։ൃऀͷͨΊͷϚΠΫϩνϡʔχϯά
جૅฤ: Treeshake + DCE
ESM Treeshake όϯυϥ(rollup/webpack)͕ ESM ͷະ༻ import Λআ͢Δػ ೳ import {a,
b} from "x"; console.log(a); // όϯυϧ࣌ʹ b ͕ফ͑Δ ※ ͨͩ͠ side effect (ޙड़) ͕ͳ͍લఏ
Treeshake ͷલఏΛ͑Δ τοϓϨϕϧͰ෭࡞༻Λى͜͢ͱ Treeshake Ͱ͖ͳ͘ͳΔ // test_shakable.js const offset =
new Date().getTimezoneOffset(); export const getOffset = () => offset; $ npx agadoo test_shakable.js # Rich-Harris/agadoo Failed to tree-shake test_shakable.js » new Date().getTimezoneOffset() ͕ Side Effect » جຊతʹτοϓϨϕϧͰ࣮ߦ͞ΕΔίʔυΛॻ͔ͳ͍
DCE: Dead Code Elimination ະ༻ίʔυΛআ͢Δ֤छ minifier ͷػೳ // source if(false){
unused; } export const x = true ? f() : -1; function f(){ return 1; unused;} // ΠϯϥΠϯల։ // out export const x=1;
Treeshake+DCEͷ࣮ફ
ݕূ༻ rollup.config.js import ts from "rollup-plugin-ts"; import { terser }
from "rollup-plugin-terser"; import replace from "@rollup/plugin-replace"; export default { plugins: [ ts({/* ུ */}), replace({ "process.env.NODE_ENV": JSON.stringify('production') }), terser(/* ུ */), ], }
ࠓճͷιʔείʔυ import { prod, dev } from "./sub"; // prod=0,
dev=1 export const ex = process.env.NODE_ENV === "production" ? prod : dev;
1. ఆల։ » process.env.NODE_ENV=production import { prod, dev } from
"./sub"; export const ex = "production" === "production" ? prod : dev;
2. ఆಉ࢜ͷධՁ » "production"==="production" => true import { prod, dev
} from "./sub"; export const ex = true ? prod : dev;
3. DCE » true?prod:dev => prod import { prod }
from "./sub"; export const ex = prod;
4. Bundle with Treeshake » prod=0 ͷΈల։ const prod =
0; export const ex = prod;
5. terser compress » ϩʔΧϧม໊Λѹॖ const o=0;export{ex as o}
Treeshake+DCE ͷ͍ํ » ڥ͝ͱʹఆల։Ͱ if(false){...} ͳ Dead Code Λ࡞Δ »
ϥΠϒϥϦ࡞ऀ: treeshakable ͳ API ઃܭΛ͢Δ » αΠζࢹͩͱϝιουνΣʔϯආ͚Δ » ϥΠϒϥϦར༻ऀ: ඞཁͳίʔυ͚ͩ import » ಛʹ import * as ... Λආ͚Δ » Ұ෦ͷϥΠϒϥϦ NODE_ENV=production ͰϏϧυ࣌࠷దԽ
ϚΠΫϩνϡʔχϯά্ڃฤ
terser ͱྑ͘ͳΔ » ΊͬͪΌݡ͍͜ͱΛ͢Δ͚Ͳҙ֎ͱ͙͢ఘΊΔͷͰࢹֶͯ͠΅͏ » https://try.terser.org/ ͕༑ୡ » ެ։ API
Ҏ֎શ෦ 1~2 จࣈʹ͢Δؾ࣋ͪͰ
compress: Կ͕͘ͳΔ͔ʁ // source const long_long_name_1: string = 'a'; const
long_long_name_2: string = 'b'; export const exported_name_is_not_shrinkable = long_long_name_1 + long_long_name_2; // out const o="ab";export{o as exported_name_is_not_shrinkable}; » ϩʔΧϧม֎ʹग़ͳ͍ͷͰ compress ର (module લఏ) » export ͞ΕΔ໊લ͘ͳΒͳ͍
compress: ϝϯόΞΫηεَ //source const x = { _private_value: 1, f()
{ return this._private_value;}, unused_prop2: 2, unused_prop3: 3, }; export const f = x.f; // out const e={_private_value:1,f(){return this._private_value}, unused_prop2:2,unused_prop3:3}.f;export{e as f};
compress: ΦϒδΣΫτΛΊΔͱ //source const private_value = 1; const unused_prop2 =
2; const unused_prop3 = 3; export const f = () => private_value; // out const o=()=>1;export{o as f};
͞Βʹൃలฤ: ෳճ minify // source const x = { A:
{ B: { v: 2, C: { D: { v:4, E: { F: { v: 6 } } }}} }}; console.log(x.A.B.v,x.A.B.C.D.v,x.A.B.C.D.E.F.v); /*1*/ const v={B:{v:2,C:{D:{v:4,E:{F:{v:6}}}}}};console.log(v.B.v,v.B.C.D.v,v.B.C.D.E.F.v); /*2*/ const v={v:2,C:{D:{v:4,E:{F:{v:6}}}}};console.log(v.v,v.C.D.v,v.C.D.E.F.v); /*3*/ const o=2,v={D:{v:4,E:{F:{v:6}}}};console.log(o,v.D.v,v.D.E.F.v); /*4*/ const o={v:4,E:{F:{v:6}}};console.log(2,o.v,o.E.F.v); /*5*/ const o=4,c={F:{v:6}};console.log(2,o,c.F.v); /*6*/ console.log(2,4,6); » terser ΞΫηεઌͷఆఆΛઙ͔ͬͯ͘͠ͳ͍ʂ » compress: { passes: 6 } (default: 1)
શ෦ఆԽͳΜͯ͑ΒΕͳ͍ਓ mangle.properties.regex ͕࠷ޙͷखஈ // rollup plugins terser({ mangle: { properties:
{ regex: "^_" } } }), ਖ਼نදݱΛຬͨͨ͠ϓϩύςΟΛ mangle ରʹ͢Δ ຊʹ ^_ ͕ϓϥΠϕʔτ͔Ͳ͏͔ਓ͕ؒ֬ೝ͠·͠ΐ͏
ϚΠΫϩνϡʔχϯά: TS ฤ (LTͰ࣌ؒແ͍ͷͰεΩοϓ)
TS: enum Λආ͚Δ // source enum XXX { AAA, BBB
} XXX[XXX.AAA]; // out var XXX; (function (XXX) { XXX[XXX["AAA"] = 0] = "AAA"; XXX[XXX["BBB"] = 1] = "BBB"; })(XXX || (XXX = {})); XXX[XXX.AAA];
TS: const enum Λ͏ // source const enum XXX {
AAA, BBB } console.log(XXX.AAA, XXX.BBB); // out console.log(0,1); » "preserveConstEnum": false ͰݩΩʔΛফͤΔ » ݩΩʔ͕Βͳ͍ͷͰ XXX[XXX.AAA] Ͱ͖ͳ͍
TS: private ҙຯͳ͍ class C { constructor(private __private_x: number) {}
private _private_method() { return this.__private_x;} public f() { return this._private_method();} } console.log(new C(1).f()); // out console.log(new class{constructor(t){this.__private_x=t}_private_method() {return this.__private_x}f(){return this._private_method()}}(1).f()); » terser TS ͷܕใͷ߹ͳΜͯΒͳ͍
TS: ߏମʹ named tuple Λ͏ type Range = [start: number,
end: number]; const range: Range = [1, 3]; const inRange = (x: number, [start, end]: Range) => { return start <= x && x <= end; } » ݻఆͷྻͷϝϯόʹ໊લΛ͚ͭΔ͜ͱ͕Ͱ͖Δ » ϓϩύςΟ໊͕ index ͳͷͰม໊ͷίετ͕গͳ͍ » (3 ݸҎ্ͩͱਓ͕ؒ͠ΜͲ͘ͳͬͯ͘Δ)
TS: ύϑΥʔϚϯεͷͨΊͷ tsconfig.json { "compilerOptions": { "target": "es2019", // 2017
Ҏ߱ async await Λม͠ͳ͍ "importHelpers": true, // tslib Λ͏ "preserveConstEnums": false, // enum ͷΠϯϥΠϯల։Λڧ੍ "noUnusedLocals": true, // ະ༻มͷܯࠂ "noUnusedParameters": true, // ະ༻Ҿͷܯࠂ "importsNotUsedAsValues": "error", // import type ͷڧ੍ } }
࣮ફ݁Ռͷհ
࣮ફ݁Ռ: @mizchi/mints » αΠζಛԽͷ TypeScript ίϯύΠϥ: 8.1 kb(gzip) // npm
install --save @mizchi/mints import { transformSync } from "@mizchi/mints"; const out = transfromSync("const x: number = 1;"); console.log(out.code); // const x=1;
Ͳ͏ͬͯখ͔ͨ͘͞͠ » ࣗ࡞ύʔαίϯϏωʔλͰ named tuple ͷߏจఆٛΛు͘ » ߏจఆٛΛ cbor ͰόΠφϦʹѹॖ
» ϥϯλΠϜʹόΠφϦΛΠϯϥΠϯԽ » ϕϯνऔΔͱ֎෦ binary Λ fetch ͢ΔΑΓஅવ͔ͬͨ » (ASIະରԠͰ prettier Λલఏ)
None
Shakerphobia ͷհ » ࡞ https://shakerphobia.netlify.app/ » bundlephobia ͰΘ͔Βͳ͍ treeshake ޙͷαΠζΛܭଌ
» skypack + webworker + rollup ͰϒϥβͰϏϧυ
·ͱΊ » ͳΜʹͤΑ Treeshake ͷཧղ͕େࣄ » terser ϝϯόΞΫηεʹऑ͍ » ಛʹΦϒδΣΫτఆΛආ͚Α͏
» ࠷ऴखஈͱͯ͠ mangle.properties.regex » ϥΠϒϥϦ࡞ऀґଘπϦʔ্ͷෛՙ͔ͩΒؤுΕ (কདྷతʹ TS ܕใͬͯ Side Effect ఆ͢Δ minifier ͕ग़Δͱࢥ͏͚Ͳɺݱঢ়ͳ͍Ͱ͢)
͓ΘΓ