diff --git a/browser-and-ui-3/package.json b/browser-and-ui-3/package.json new file mode 100644 index 0000000..b11b4f4 --- /dev/null +++ b/browser-and-ui-3/package.json @@ -0,0 +1,15 @@ +{ + "name": "@slide/browser-and-ui-3", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "dev": "slidev", + "build": "slidev build", + "export": "slidev export" + }, + "keywords": [], + "author": "", + "license": "MIT", + "description": "" +} diff --git a/browser-and-ui-3/public/img/terser.org_.png b/browser-and-ui-3/public/img/terser.org_.png new file mode 100644 index 0000000..525e980 Binary files /dev/null and b/browser-and-ui-3/public/img/terser.org_.png differ diff --git a/browser-and-ui-3/slides-export.pdf b/browser-and-ui-3/slides-export.pdf new file mode 100644 index 0000000..74db1cc Binary files /dev/null and b/browser-and-ui-3/slides-export.pdf differ diff --git a/browser-and-ui-3/slides.md b/browser-and-ui-3/slides.md new file mode 100644 index 0000000..46ed4cc --- /dev/null +++ b/browser-and-ui-3/slides.md @@ -0,0 +1,313 @@ +--- +theme: ../theme-browser-and-ui +titleTemplate: '%s - ken7253' +layout: intro +--- + +# Browser and UI +\#3 Network/Performance + +--- +src: "../theme-browser-and-ui/me.md" +--- + +--- +src: "../theme-browser-and-ui/description.md" +--- + +--- +layout: intro +--- + +# バンドルサイズを半減させた話 +\#3 Network/Performance + +--- + +## プロジェクトの前提 + +- 組み込みブラウザ上で動作するアプリケーション +- 古いモデルでChromium 58ぐらいで、一部Safari 11ぐらいの環境も +- webpack/babelで素朴なSPAを構築 + +--- +layout: section +--- + +## Q:サイズを削減しやすい環境とは? + +--- +layout: section +--- + +## A:元のバンドルサイズが大きい + + + +--- + +## やったこと + +- コンパイルターゲットをES5からES6に +- Terserの設定で`mangle:false`になっていたのを解消 +- 不要なコードの削除 + +作業としては上の2つがメイン、コードの削除は段階的に実施 + +--- + +### コンパイルターゲットをES5からES6に + +1. webpackを利用しているのでwebpackの設定を変更 +2. 大きめのリリースに混ぜてQAが実施されるのでそれに混ぜてリリース + +```diff +// webpack.config.js +{ + // ... +- target: ['web', 'es5'], ++ target: ['web', 'es6'], + // ... +} +``` + + +この対応で`6.1MB`->`3.74MB`にバンドルサイズを削減。 + +--- +layout: section +--- + +## なぜES5はサイズが大きくなるか + +--- + +## なぜES5はサイズが大きくなるか + +- ESMが使えないためTree shakingが効かない +- アロー関数から関数宣言への変換 +- Generatorが存在せず非同期処理のコードが冗長になりがち + +ほとんどのサービスでは意味がないので`ES5`へのトランスパイルはやめるべき + + + +--- +layout: section +--- + +## 一般的なアプリケーションの指標は? + +--- +layout: section +--- + +## Baseline(Widely available)にあわせる + + + +--- +layout: section +--- + +## 特殊な事情がある場合は、ES2017/ES2020を目指すとよさそう + + + +--- + +## 特殊な事情がある場合 + +今回のバンドルサイズ調整ではES2020を目指していた。 + +- Optional chaining(オプショナルチェーン`a?.b`) +- Nullish coalescing(Null 合体演算子 `a ?? b`) + +上記の機能はES2020で追加されたものでよく使われている。 + +一方で、トランスパイル時のサイズが増えがちだった。 + + + +--- + +## 特殊な事情がある場合 + +### Optional chaining(オプショナルチェーン) + +```ts +// src: 9 Bytes +a?.b?.c +// downlevel: 100 Bytes +var _a; +(_a = a) === null || _a === void 0 || (_a = _a.b) === null || _a === void 0 ? void 0 : _a.c; +// minfy: 64 Bytes x7.1! +var l;null===(l=a)||void 0===l||null===(l=l.b)||void 0===l||l.c; +``` + +### Nullish coalescing(Null 合体演算子) + +```ts +// src: 7 Bytes +a ?? b; +// downlevel: 52 Bytes +var _a; +(_a = a) !== null && _a !== void 0 ? _a : b; +// minfy: 34 Bytes x4.8! +var l;null!==(l=a)&&void 0!==l||b; +``` + + + +--- +layout: section +--- + +## Terserの設定で`mangle:false`になっていたのを解消 + +--- + +## Terserとmangleとは? + +![terser.orgのスクリーンショット](/img/terser.org_.png) + +--- + +## Terserとmangleとは? + +### Terser + +JSのminifyを行うツール + +### mangle + +変数名などを短くしてminifyを行う方法 + +--- + +## なぜ`mangle:false`になっていたのか + +依存ライブラリの一部がmangleを行うと壊れたため + +リリースのために一時的に`mangle:false`されていたのが放置されていた。 + +- 調査ログなどが軽く当時のPRに書いてあったのでそれを確認 +- ライブラリ側のアップデートで修正されていたのが確認 +- ライブラリをアップデート +- 記述を削除してリリース + +`4.11MB`->`2.95MB`に削減 + +--- + +## 不要なコードの削除 + +- 開発中しか利用しないコードのバンドルを防ぐ +- 重複しているコードを共通化する + +--- + +### 開発中しか利用しないコードのバンドルを防ぐ + +````md magic-move + +```ts +// mock.ts +export const worker = setupWorker(...handlers); + +/* ============================================ */ + +import { worker } from "./mock.ts"; +// mswのモックを有効化する処理 +const initApp = () => { + if ( + (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') && + process.env.USE_MOCK === 'true' + ) { + worker.start(); + }; + // ... +} +``` + +```ts +// mock.ts +export const worker = setupWorker(...handlers); + +/* ============================================ */ + +// mswのモックを有効化する処理 +if (process.env.NODE_ENV === 'development') { + if (process.env.ENABLE_MSW === 'true') { + import("./mock.ts").then((worker) => worker.start()) + } +}; + +const initApp = () => { + //... +} +``` +```` + +- デットコード削除の対象になるようにダイナミックインポートに + +--- + +## 重複しているコードを削除・共通化する + +ここはほぼおまけ程度 + +- ダイアログやローディングなど共通化できる部分を共通化 +- リファクタリングの作業を進めていくと自然とコード量が減っていく +- 型情報から不要だと分かるオプショナルチェーンや初期値の代入を削る + +`2.95MB` -> `2.83MB` + +--- +layout: section +--- + +## ざっくりとバンドルサイズを半減できた + +--- +layout: section +--- + +## まとめ + +--- + +## まとめ + +### ES5に変換してはいけない + +- トランスパイルターゲットもBaseline(Widely available)に合わせていく +- 特殊な環境の人は頑張って自分たちで答えを出そう +- ES2017/ES2020が大きな目標かも + +### 定期的にビルド設定の見直しを + +- サポートブラウザと共に定期的に見直す +- きちんと想定したバージョンにトランスパイルされているか確認する + +### 無駄なコードを書かない + +- 静的解析とレビューでカバー + +--- +layout: end +--- diff --git a/browser-and-ui-3/styles/index.ts b/browser-and-ui-3/styles/index.ts new file mode 100644 index 0000000..88a6bdd --- /dev/null +++ b/browser-and-ui-3/styles/index.ts @@ -0,0 +1 @@ +import "./mod.css" diff --git a/browser-and-ui-3/styles/mod.css b/browser-and-ui-3/styles/mod.css new file mode 100644 index 0000000..1d783b5 --- /dev/null +++ b/browser-and-ui-3/styles/mod.css @@ -0,0 +1,12 @@ +h1, h2, h3, h4, h5, h6 { + line-height: 1.6 !important; +} + +.slidev-layout h2:not(:first-child), +.slidev-layout h3:not(:first-child), +.slidev-layout h4:not(:first-child), +.slidev-layout h5:not(:first-child), +.slidev-layout h6:not(:first-child) { + margin-bottom: 0 !important; + margin-top: 16px; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f08ad98..ce71b20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,9 @@ "pepc", "browser-and-ui-2", "css-polyfill", - "beyond-early-returns" + "beyond-early-returns", + "reduce-bundle-size", + "browser-and-ui-3" ], "dependencies": { "@iconify-json/mdi": "^1.2.3", @@ -89,6 +91,12 @@ "serve": "^14.2.4" } }, + "browser-and-ui-3": { + "name": "@slide/browser-and-ui-3", + "version": "1.0.0", + "license": "MIT", + "devDependencies": {} + }, "css-polyfill": { "name": "@slide/css-polyfill", "version": "1.0.0", @@ -2171,6 +2179,10 @@ "resolved": "browser-and-ui-2", "link": true }, + "node_modules/@slide/browser-and-ui-3": { + "resolved": "browser-and-ui-3", + "link": true + }, "node_modules/@slide/css-polyfill": { "resolved": "css-polyfill", "link": true @@ -15397,6 +15409,13 @@ "version": "1.0.0", "license": "MIT" }, + "reduce-bundle-size": { + "name": "@slide/reduce-bundle-size", + "version": "1.0.0", + "extraneous": true, + "license": "MIT", + "devDependencies": {} + }, "reuse": { "name": "@slide/reuse", "version": "1.0.0", diff --git a/package.json b/package.json index c028a5a..adbd0e6 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,9 @@ "pepc", "browser-and-ui-2", "css-polyfill", - "beyond-early-returns" + "beyond-early-returns", + "reduce-bundle-size", + "browser-and-ui-3" ], "devDependencies": { "@chromatic-com/storybook": "^3.2.4", diff --git a/theme-browser-and-ui/styles/layout.css b/theme-browser-and-ui/styles/layout.css index 0a87c1b..e34ec14 100644 --- a/theme-browser-and-ui/styles/layout.css +++ b/theme-browser-and-ui/styles/layout.css @@ -45,6 +45,7 @@ p { font-size: 1.5rem; margin: 1.5rem 0; + line-height: 1.6; } blockquote {