Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Optimize the size of your SPA, битва за байты

Dmitry Patsura
September 07, 2019

Optimize the size of your SPA, битва за байты

2019 год, современный веб, PWA, SPA, bundle на фронте от одного мегабайта javascript. Стоп! Мы перестали ставить в приоритет экономию трафика и TTI пользователей, как делали это раньше. Пришло время разобраться в техниках оптимизации размера JS/CSS/IMAGE. Это битва за байты и мы ее начинаем.

Видео: https://youtu.be/A_fzyRC6XvU?t=8338
GitHub: https://github.com/ovr
Twitter: https://twitter.com/ovrweb

Dmitry Patsura

September 07, 2019
Tweet

More Decks by Dmitry Patsura

Other Decks in Technology

Transcript

  1. Автоматизированный pipeline помогающий готовить NodeJS c GraphQL через сообщение в

    telegram, используя консольный клиент, запущенный в VSCode. (и немножко про AST)
  2. • Компрессия • Минификация • Code splitting/bundling/tree shaking • Главная

    проблема мира JavaScript • Главная проблема мира Dart • Polyfills • Альтернативные библиотеки • В заключение Поговорим 4
  3. Зачем это все? 40% уходят при загрузке больше 3 секунд

    +7% на каждую дополнительную секунду 6
  4. Компрессия gzip Deflate — это алгоритм сжатия без потерь, использующий

    комбинацию алгоритмов LZ77 и Хаффмана. gzip = GNU ZIP 14
  5. Компрессия gzip gzip -1 -c vendor.js | wc -c |

    numfmt --to=iec-i --suffix=B --padding=10 1 421KiB 2 399KiB 3 381KiB 4 356KiB 5 340KiB 6 333KiB 7 331KiB 8 329KiB 9 329KiB
  6. Компрессия Brotli Метод сжатия основан на современном варианте алгоритма LZ77,

    энтропийном кодировании Хаффмана и моделировании контекста 2-го порядка.ка.
  7. Компрессия brotli brotli -1 -c vendor.js | wc -c |

    numfmt --to=iec-i --suffix=B --padding=10 1 391KiB 2 358KiB 3 350KiB 4 336KiB 5 308KiB 6 303KiB 7 300KiB 8 298KiB 9 296KiB 11 268KiB
  8. Минификация optimization: { minimizer: [ new TerserPlugin({ extractComments: true, }),

    ], }, ├── app.3f65094c2a1291a425ba.js ├── app.3f65094c2a1291a425ba.js.LICENSE
  9. export { default as add } from './add.js'; export {

    default as after } from './after.js'; export { default as ary } from './ary.js'; export { default as assign } from './assign.js'; //...... export { default } from './lodash.default.js'; node_modules/lodash-es/lodash.js lodash-es provides ES modules
  10. Начинаем оптимизировать Webpack Deep Scope Analysis Plugin https://github.com/vincentdchan/webpack-deep-scope-analysis-plugin A webpack

    plugin for deep scope analysis. It's a project of GSoC 2018 webpack organization. It's a plugin to improve tree-shaking. It can make webpack eliminate the unused imports related to the unused exports. It solves the issue 6254 for webpack. Student: @Vincent Mentor: @Tobias 45
  11. Начинаем оптимизировать import { isNull } from 'lodash-es'; var fun

    = 1; fun = function scope(...args) { return isNull(...args); } export { fun } Re-assign function to variable
  12. Начинаем оптимизировать function foobar() {} function foo() { var a

    = foobar(); var b = 8; return 10; } console.log(foo()); function foobar() {} function foo() { foobar(); return 10; } console.log(foo()); Input Result
  13. Начинаем оптимизировать function foobar() {} function foo() { var a

    = /* @__PURE__ */ foobar(); var b = 8; return 10; } console.log(foo()); function foobar() {} function foo() { return 10; } console.log(foo()); Input Result
  14. splitChunks: { chunks: 'async', minSize: 30000, maxSize: 0, minChunks: 1,

    maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: '~', automaticNameMaxLength: 30, name: true, },
  15. export async function getDeviceId(): Promise<string> { const fp2 = await

    import('fingerprintjs2'); const components = await fp2.getPromise(); return fp2.x64hash128( components.map((pair) => pair.value).join(), 31 ); }
  16. optimization: { splitChunks: { chunks: 'all', cacheGroups: { fp2: {

    test: /[\\/]fingerprintjs2[\\/]/, name: 'fp2', chunks: 'all', }, vendors: { reuseExistingChunk: true, }, }, }, },
  17. Минификация Google Closure Compiler / GCC The Closure Compiler is

    a tool for making JavaScript download and run faster. Instead of compiling from a source language to machine code, it compiles from JavaScript to better JavaScript. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. 68
  18. Главная проблема dart2js • Load kernel -> kernel AST •

    Model • Tree-shake and create world • Analyze • codegen model • codegen and tree-shake • emit 73
  19. Polyfills browserlist The config to share target browsers and Node.js

    versions between different front-end tools. It is used in: • Autoprefixer • Babel • postcss-preset-env • eslint-plugin-compat • stylelint-no-unsupported-browser-features • postcss-normalize • obsolete-webpack-plugin 78
  20. Polyfills useBuiltIns "usage" | "entry" | false, defaults to false.

    This option configures how @babel/preset-env handles polyfills. 83
  21. Polyfill.io Upgrade the web. Automatically. It's a service which accepts

    a request for a set of browser features and returns only the polyfills that are needed by the requesting browser.
  22. <!-- Browsers with ES module support load this file. -->

    <script type="module" src=“/bundle.mjs” /> <!-- Older browsers load this file (and module-supporting --> <!-- browsers know *not* to load this file). --> <script nomodule src=“/bundle.es5.js” /> Two bundles, one for new, one for old
  23. Альтернативные A tiny routing solution for modern React apps that

    relies on Hooks. A router you wanted so bad in your project!
  24. В заключение • Cache/Expire • E-Tag • HSTS • CDN

    • DNS-PREFETCH • PRECONNECT • И много еще всего :)