Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
バンドル最適化マニアクス 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
16
8.5k
CI/CD 改善の勘所
mizchi
0
270
極限環境で最終ビルドを絞るためのフロントエンド設計
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
ソニーのクラウド共通基盤の変遷とAI時代の開発スタイルに合わせた進化 / The Journey of Sony’s Common Cloud Platform and Its Evolution for AI-Native Development
kenjiyoneyama
0
170
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
560
Starting & Sustaining Code-Based E2E Testing for Non-Coding QA Teams( #jasstniigata )
teyamagu
PRO
1
680
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
250
GitHubハンズオン講座 — 実務レベルのチーム開発のフローを身につけよう
junhat6
0
110
Webの地図
yosuke_furukawa
PRO
6
4.9k
ハーネス設計入門 〜 基礎知識の整理から実務へのステップアップ 〜
kinopeee
18
19k
スマートフォンでモールス信号を送受信する 〜スマートフォンのLEDとカメラで作る光通信の設計と実装〜
atsuki_seo
0
210
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
490
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
9k
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
330
Featured
See All Featured
Darren the Foodie - Storyboard
khoart
PRO
4
4k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
250
1.3M
Un-Boring Meetings
codingconduct
0
430
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
290
Ruling the World: When Life Gets Gamed
codingconduct
0
370
The World Runs on Bad Software
bkeepers
PRO
72
12k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
WENDY [Excerpt]
tessaabrams
14
39k
Building a Scalable Design System with Sketch
lauravandoore
464
34k
Raft: Consensus for Rubyists
vanstee
142
7.7k
KATA
mclloyd
PRO
35
16k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
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 ͕ग़Δͱࢥ͏͚Ͳɺݱঢ়ͳ͍Ͱ͢)
͓ΘΓ