Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

Menguak Misteri Module Bundler

106 visualizaciones

Publicado el

Pernah bingung gimana caranya sebuah framework menghasilkan sebuah kode output yang berbeda dengan kode yang kamu tulis? Penasaran sebetulnya apa yang terjadi dibalik layar dan gimana caranya kamu bisa belajar dari hal itu untuk memperbaiki kode yang kamu hasilkan?

Publicado en: Tecnología
  • Sé el primero en comentar

  • Sé el primero en recomendar esto

Menguak Misteri Module Bundler

  1. 1. Menguak Misteri Module Bundler
  2. 2. Halo, saya Riza!
  3. 3. @rizafahmi22 #livecampid
  4. 4. Agenda Demo aplikasi Menulis JS yang lebih modular Menggunakan Module Bundler
  5. 5. 🍀 Vanilla Leaderboard https://vanilla-leaderboard.web.app
  6. 6. 🍀 Vanilla Leaderboard
  7. 7. 🍀 Vanilla Leaderboard confetti-js
  8. 8. 🍀 Vanilla Leaderboard lil-uuid
  9. 9. 🍀 Vanilla Leaderboard xStore
  10. 10. 🍀 Vanilla Leaderboard dayjs
  11. 11. 🍀 Vanilla Leaderboard workbox
  12. 12. 6 requests hanya untuk JS 😱
  13. 13. Vendors
  14. 14. #!/usr/bin/env bash set -e deps=( "gh/lil-js/uuid@0.1.1/uuid.min.js" "gh/florian/xStore@2.0.4/src/xStore.min.js" "npm/confetti-js@0.0.18/dist/index.min.js" "npm/dayjs@1.8.21/dayjs.min.js" "npm/dayjs@1.8.21/plugin/relativeTime.js" ) for i in "${deps[@]}" do curl "https://cdn.jsdelivr.net/${i}" -L echo ";" done $ ./buildVendors.sh > vendors.js
  15. 15. ✅ Concatenation ✅ Minification
  16. 16. Solusi yang bagus
  17. 17. di 2008 Solusi yang bagus
  18. 18. Solusi yang lebih baik • Proses update dependencies yang lebih mudah • Tidak khawatir terhadap dependencies of dependencies • Urutan dari import tidak menjadi masalah
  19. 19. JavaScript Modules
  20. 20. function add(a, b) { return a + b; } function sub(a, b) { return a - b; } function mul(a, b) { return a * b; } function div(a, b) { return a / b; } basic_calc.js
  21. 21. advance_calc.js function squared(a) { return mul(a, a); }
  22. 22. calc.html <script src="js/basic_calc.js"></script> <script src=“js/advance_calc.js"></script> <script> console.log(squared(4)); console.log(add(3, 4)); console.log(mul(3, 5)); </script> Semuanya jadi global 😢
  23. 23. Bungkus Menjadi Fungsi
  24. 24. let BasicCalc = function() { return { add: function(a, b) { return a + b; }, sub: function(a, b) { return a - b; }, mul: function(a, b) { return a * b; }, div: function(a, b) { return a / b; } }; }; basic_calc.js
  25. 25. advance_calc.js let AdvanceCalc = function() { return { squared: function squared(a) { return BasicCalc().mul(a, a); } }; };
  26. 26. calc.html Ok, tapi jadi aneh 🤔 <script src="js/basic_calc.js"></script> <script src=“js/advance_calc.js"></script> <script> console.log(AdvanceCalc().squared(4)); console.log(BasicCalc().add(3, 4)); console.log(BasicCalc().mul(3, 5)); </script>
  27. 27. iifeImmediately Invoked Function Expression
  28. 28. let add = function (a, b) { return a + b; } console.log(add(1, 2));
  29. 29. let add = (function (a, b) { return a + b; })(1, 2); console.log(add);
  30. 30. let BasicCalc = function() { return { add: function(a, b) { return a + b; }, sub: function(a, b) { return a - b; }, mul: function(a, b) { return a * b; }, div: function(a, b) { return a / b; } }; }; basic_calc.js
  31. 31. basic_calc.js let BasicCalc = (function() { return { add: function(a, b) { return a + b; }, sub: function(a, b) { return a - b; }, mul: function(a, b) { return a * b; }, div: function(a, b) { return a / b; } }; })();
  32. 32. advance_calc.js let AdvanceCalc = function() { return { squared: function squared(a) { return BasicCalc().mul(a, a); } }; };
  33. 33. advance_calc.js let AdvanceCalc = (function() { return { squared: function squared(a) { return BasicCalc.mul(a, a); } }; })();
  34. 34. calc.html <script src="js/basic_calc.js"></script> <script src=“js/advance_calc.js"></script> <script> console.log(AdvanceCalc().squared(4)); console.log(BasicCalc().add(3, 4)); console.log(BasicCalc().mul(3, 5)); </script>
  35. 35. calc.html <script src="js/basic_calc.js"></script> <script src="js/advance_calc.js"></script> <script> console.log(AdvanceCalc.squared(4)); console.log(BasicCalc.add(3, 4)); console.log(BasicCalc.mul(3, 5)); </script>
  36. 36. Suatu saat kita butuh sistem modulasi yang dapat digunakan di aplikasi atau proyek berbeda
  37. 37. Module System • Sintaksis yang lebih sederhana untuk import/export • Bisa dengan mudah mendefinisikan modul di file terpisah • Bisa saling import Must have!
  38. 38. Module System • Menghindari name collision • Import modul secara async • Bisa di browser atau di server via node.js Nice to have!
  39. 39. JS Module System
  40. 40. Module System • Globals • CommonJS • Asynchronous Module Definition (AMD) • Universal Module Definition (UMD) • ES2015 Module (ESM) • Lainnya…
  41. 41. globals var $, jQuery; $ = jQuery = (() => { return { /* ... */ } })(); // usage $('.btn-success').remove();
  42. 42. Globals • Naming collisions 👎 • Urutan import harus diperhatikan 👎 • Tidak bisa import sebagian modul yang dibutuhkan 👎 • Hanya bisa menggunakan pustaka dari CDN 👎
  43. 43. CommonJS // calc.js const calc = { /* ... */ } module.exports = calc; // app.js const calc = require('./calc.js'); calc.add(1, 3); // other_app.js const { add } = require('./calc.js'); calc.add(1, 3);
  44. 44. CommonJS • Tidak terjadi naming collision 👍 • Pustaka banyak tersedia via npm 👍 • Dapat digunakan di server via Node.js 👍 • Belum bisa untuk di browser 👎 • Hanya bisa import secara synchronous 👎
  45. 45. Asynchronous Module Definition // lib.js define('yayQuery', ['yayQueryUI'], function(yayQueryUI) { // returns the exported value return function() { // ... }; }); // app.js // define path requirejs.config({ baseUrl: 'js/lib/', paths: { yayquery: 'yayquery-1.1.1' } }); define(['yayquery'], function($) { // this is executed only when yayquery and it's deps are loaded });
  46. 46. Require.JS/AMD • Async module 👍 • Bisa berjalan di browser dan server 👍 • Kode boilerplate cukup banyak 👎
  47. 47. Universal Module Definition (function(root, factory) { if (typeof exports === 'object') { // CommonJS module.exports = factory(require('dep')); } else if (typeof define === 'function' && define.amd) { // AMD define(['dep'], function(dep) { return (root.returnExportsGlobal = factory(dep)); }); } else { // Globals root.myModule = factory(root.dep); } })(this, function(dep) { // Your actual module return {}; });
  48. 48. Universal Module Definition • Semua jenis modul bisa digunakan 👍 • Kode pembungkus cukup kompleks, sepertinya sulit ditulis manual 👎
  49. 49. ES2015 Modules // calc.js const add = (a, b) => a + b; const sub = (a, b) => a - b; const mul = (a, b) => a * b; const div = (a, b) => a / b; export { add, sub, mul, div }; // app.js import { add } from './calc.js'; console.log(add(1, 3));
  50. 50. ES2015 Modules <html> <body> <!-- ... --> <script type="module"> import { add } from ‘./basic_calc.js'; console.log(add(1, 3)); </script> </body> </html>
  51. 51. ES2015 Modules • Secara sintaksis mirip dengan CommonJS • (Hampir) menjadi format baku 👍 • (Hampir) dapat berjalan di browser dan server 👍
  52. 52. Mari Kita Coba
  53. 53. const BasicCalc = require('./basic_calc.js'); function squared(a) { return BasicCalc.mul(a, a); } CommonJS
  54. 54. ESM import { mul } from './basic_calc.js'; function squared(a) { return mul(a, a); }
  55. 55. Module Bundler
  56. 56. Alat bantu untuk melakukan bundle JavaScript modules menjadi satu file dan dan dapat dijalankan di browser.
  57. 57. Fitur Penting Lainnya • Sistem modulasi belum sepenuhnya didukung oleh browser • Menangani dependencies dan hubungan dengan dependencies lain • Dapat pula digunakan untuk gambar, CSS dan aset lainnya.
  58. 58. Fitur Tambahan • Menjalankan development server • Tree shaking • Membuat source map otomatis • Code splitting
  59. 59. Konsep Umum Bundler • Entry point: file utama yang akan dicek oleh bundler • Output: File akhir yang akan digunakan • Loaders: Algoritma parsing yang ingin digunakan seperti babel, typescript, dll. • Plugins: Fitur tambahan yang dibutuhkan.
  60. 60. $ npm install webpack webpack-cli
  61. 61. basic_calc.js function add(a, b) { return a + b; } function mul(a, b) { return a * b; } export { add, mul };
  62. 62. advance_calc.js import { mul } from './basic_calc.js'; function squared(a) { return mul(a, a); } export { squared };
  63. 63. import { add, mul } from './basic_calc.js'; import { squared } from './advance_calc.js'; console.log(add(1, 3)); console.log(mul(2, 4)); console.log(squared(4)); main.js
  64. 64. $ npx webpack js/main.js
  65. 65. const modules = { 'basic_calc.js': function(exports, require) { exports.add = function(a, b) { return a + b; }; exports.mul = function(a, b) { return a * b; }; }, 'advance_calc.js': function(exports, require) { const mul = require('basic_calc.js').mul; exports.squared = function(a) { return mul(a, a); }; }, 'main.js': function(exports, require) { const add = require('basic_calc.js').add; const mul = require('basic_calc.js').mul; const squared = require('advance_calc.js').squared; console.log(add(1, 3)); console.log(mul(2, 4)); console.log(squared(4)); } }; webpackStart({ modules, entry: 'app.js' }); Ilustrasi Webpack
  66. 66. 🍀 Leaderboard
  67. 67. $ npm install confetti-js dayjs lil-uuid xStore
  68. 68. module.exports = { entry: ['./js/app.js'], output: { path: __dirname + '/dist', filename: 'bundle.webpack.js' }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] } // plugins: [] }; webpack.config.js
  69. 69. module.exports = { entry: ['./js/app.js'], output: { path: __dirname + '/dist', filename: 'bundle.webpack.js' }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] } // plugins: [] }; webpack.config.js Entry point
  70. 70. module.exports = { entry: ['./js/app.js'], output: { path: __dirname + '/dist', filename: 'bundle.webpack.js' }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] } // plugins: [] }; webpack.config.js Output
  71. 71. module.exports = { entry: ['./js/app.js'], output: { path: __dirname + '/dist', filename: 'bundle.webpack.js' }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] } // plugins: [] }; webpack.config.js Loaders
  72. 72. module.exports = { entry: ['./js/app.js'], output: { path: __dirname + '/dist', filename: 'bundle.webpack.js' }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] } // plugins: [] }; webpack.config.js
  73. 73. $ npx webpack --config webpack.config.js
  74. 74. <html lang="en"> <body> … <script src=“dist/bundle.webpack.js"></script> </body> </html>
  75. 75. Gaya Webpack • Menggunakan module map • Menggunakan fungsi untuk membungkus setiap modul
  76. 76. rollup.js
  77. 77. $ npm install rollup rollup-plugin-babel
  78. 78. basic_calc.js function add(a, b) { return a + b; } function mul(a, b) { return a * b; } export { add, mul };
  79. 79. advance_calc.js import { mul } from './basic_calc.js'; function squared(a) { return mul(a, a); } export { squared };
  80. 80. import { add, mul } from './basic_calc.js'; import { squared } from './advance_calc.js'; console.log(add(1, 3)); console.log(mul(2, 4)); console.log(squared(4)); main.js
  81. 81. import babel from 'rollup-plugin-babel'; export default { input: 'js/main.js', output: { file: 'dist/bundle.rollup.js', format: 'iife' }, plugins: [ babel() ] }; rollup.config.js
  82. 82. import babel from 'rollup-plugin-babel'; export default { input: 'js/main.js', output: { file: 'dist/bundle.rollup.js', format: 'iife' }, plugins: [ babel() ] }; rollup.config.js Entry Point
  83. 83. import babel from 'rollup-plugin-babel'; export default { input: 'js/main.js', output: { file: 'dist/bundle.rollup.js', format: 'iife' }, plugins: [ babel() ] }; Output rollup.config.js
  84. 84. import babel from 'rollup-plugin-babel'; export default { input: 'js/main.js', output: { file: 'dist/bundle.rollup.js', format: 'iife' }, plugins: [ babel() ] }; rollup.config.js Loaders & Plugins
  85. 85. $ npx rollup -c
  86. 86. function basic_calc$add(a, b) { return a + b; } function basic_calc$mul(a, b) { return a * b; } function advance_calc$squared(a) { return basic_calc$mul(a, a); } console.log(basic_calc$add(1, 3)); console.log(basic_calc$mul(2, 4)); console.log(advance_calc$squared(4)); Ilustrasi Rollup
  87. 87. 🍀 Leaderboard
  88. 88. $ npm install confetti-js dayjs lil-uuid xStore
  89. 89. $ npm install rollup-plugin-commonjs rollup-plugin-node-resolve rollup-plugin-uglify
  90. 90. import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import babel from 'rollup-plugin-babel'; import { uglify } from 'rollup-plugin-uglify'; export default { input: 'js/app.js', output: { file: 'dist/bundle.rollup.js', format: 'iife', globals: { 'dayjs/plugin/relativeTime': 'relativeTime', dayjs: 'dayjs', xStore: 'xStore', lil: 'lil-uuid', ConfettiGenerator: 'confetti-js' } }, plugins: [ resolve(), commonjs(), babel({ exclude: 'node_modules/*' }), uglify() ] }; rollup.config.js
  91. 91. $ npx rollup -c
  92. 92. <html lang="en"> <body> … <script src=“dist/bundle.rollup.js”></script> </body> </html>
  93. 93. Gaya Rollup • Menghasilkan bundle yang lebih rata dan sederhana • Tidak menggunakan fungsi pembungkus
  94. 94. 🍀 Vanilla Leaderboard https://vanilla-leaderboard.web.app
  95. 95. 🍀 Vanilla Leaderboard https://github.com/rizafahmi/vanilla-leaderboard
  96. 96. Kesimpulan
  97. 97. Kesimpulan • Module bundler adalah alat bantu untuk membungkus JavaScript agar dimengerti browser • Bundler dibutuhkan agar aplikasi lebih modular dan dapat menggunakan sintaksis JavaScript modern • Menggunakan concatenation dan minification cukup untuk aplikasi sederhana
  98. 98. @rizafahmi22 #livecampid

×