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
7
4.2k
バンドル最適化マニアクス at tfconf
treeshake, DCE, terser mangling
Koutarou Chikuba
May 14, 2022
Tweet
Share
More Decks by Koutarou Chikuba
See All by Koutarou Chikuba
CI/CD 改善の勘所
mizchi
0
11
極限環境で最終ビルドを絞るためのフロントエンド設計
mizchi
15
5k
Server Side JavaScript のためのバンドル最適化
mizchi
5
6.8k
V8 as a container on CDN Edge worker
mizchi
6
2k
Edge Side Frontend という新領域
mizchi
34
14k
「たかがJavaScript」のその先 #TECHPLAY
mizchi
47
20k
Deno Node 両刀
mizchi
6
2.4k
「フロントエンド領域」を再定義する
mizchi
50
36k
光を超えるためのフロントエンドアーキテクチャ
mizchi
91
23k
Other Decks in Programming
See All in Programming
どうして手を動かすよりもチーム内のコードレビューを優先するべきなのか
okashoi
3
860
PHPUnitしか使ってこなかった 一般PHPerがPestに乗り換えた実録
mashirou1234
0
420
『改訂新版 良いコード/悪いコードで学ぶ設計入門』活用方法−爆速でスキルアップする!効果的な学習アプローチ / effective-learning-of-good-code
minodriven
28
3.9k
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
380
ChatGPT とつくる PHP で OS 実装
memory1994
PRO
3
190
PicoRubyと暮らす、シェアハウスハック
ryosk7
0
200
rails newと同時に型を書く
aki19035vc
5
700
週次リリースを実現するための グローバルアプリ開発
tera_ny
1
1.1k
バグを見つけた?それAppleに直してもらおう!
uetyo
0
220
Jaspr Dart Web Framework 박제창 @Devfest 2024
itsmedreamwalker
0
150
QA環境で誰でも自由自在に現在時刻を操って検証できるようにした話
kalibora
1
140
ecspresso, ecschedule, lambroll を PipeCDプラグインとして動かしてみた (プロトタイプ) / Running ecspresso, ecschedule, and lambroll as PipeCD Plugins (prototype)
tkikuc
2
1.7k
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
30
2.1k
Documentation Writing (for coders)
carmenintech
67
4.5k
Designing on Purpose - Digital PM Summit 2013
jponch
116
7.1k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
33
2.7k
Building Your Own Lightsaber
phodgson
104
6.2k
GitHub's CSS Performance
jonrohan
1030
460k
Done Done
chrislema
182
16k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
VelocityConf: Rendering Performance Case Studies
addyosmani
327
24k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3.1k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
98
18k
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 ͕ग़Δͱࢥ͏͚Ͳɺݱঢ়ͳ͍Ͱ͢)
͓ΘΓ