Showing posts with label node js. Show all posts
Showing posts with label node js. Show all posts
Thursday, June 11, 2020

Belajar Webpack Dasar Lengkap


Menggunakan module dalam pengembangan website, itu hal yang biasa. Dengan module kita dapat membuat aplikasi lebih cepat. Sebabnya, module bersifat shareable. Menggunakan satu, dua, atau tiga modul saja mungkin tidak masalah. 
Namun bagaimana jika terdapat puluhan modul yang kita gunakan dalam mengembangkan aplikasi? 

Tak jarang juga modul yang kita gunakan tergantungan terhadap modul lain. Contoh jika kita gunakan bootstrap, secara tidak langsung kita juga membutuhkan JQuery. Kenapa demikian? Bootstrap akan berjalan ketika JQuery sudah terpasang. 
Meski sudah belajar bagaimana memasang modul dengan NPM, namun untuk menggunakannya kita masih menggunakan cara lama (menggunakan tag <script>). Saat  menggunakan cara lama dalam mengelola modul JavaScript, kita tahu urutan deklarasinya sangatlah vital. Jika terdapat satu urutan penempatan tag <script> yang salah, maka aplikasi tak akan berjalan sesuai dengan harapan.
Dari permasalahan-permasalahan tersebut, jelas kita perlu tools yang memudahkan kita menggunakan modul dengan cara modern. Berita baiknya, semua hal tadi kini sudah ada solusinya. 
Menggunakan module bundler kita tidak perlu lagi memikirkan masalah di atas. Module bundler secara otomatis akan mengumpulkan semua module-module yang digunakan, mengurutkannya dengan benar dan membungkusnya menjadi satu berkas module saja. 
Salah satu module bundler yang populer digunakan pada saat ini adalah Webpack. Dengan menggunakan webpack kita dapat mengubah dynamic code dan modules menjadi static code (kode yang siap digunakan pada tahap production). 
Pada modul kali ini kita akan membahas mengenai Webpack mulai dari apa itu webpack, cara memasang dan menggunakannya, hingga menerapkannya pada proyek Club Finder yang sudah kita buat sebelumnya.

What is Webpack?

Pada dasarnya webpack merupakan module bundler untuk aplikasi JavaScript modern. Ketika webpack dijalankan pada proyek kita, di belakang layar webpack akan mengobservasi module apa saja yang kita gunakan dan membuat modul-modul tersebut dibungkus menjadi satu berkas (atau lebih).
20200313163923ddf1c4f937107ffe80d299dd072edcb2.gifIlustrasi diambil dari https://webpack.js.org/
Dengan menggunakan Webpack kita dapat leluasa menggunakan module yang saling bergantungan. Webpack akan menggabungkan seluruh module yang digunakan baik itu modul yang kita tuliskan sendiri atau module yang kita dapatkan melalui NPM menjadi static assets yang siap digunakan pada tahap produksi.

Core Concepts

Untuk lebih memahami bagaimana webpack bekerja, ketahui dulu core concepts yang ada pada webpack.
20200313170447aa5038400842a2473e645458aeb8d7ea.png
Terdapat 5 (lima) konsep penting dalam webpack yang perlu kita ketahui sebelum menggunakan webpack itu sendiri. Dari 5 (lima) konsep tersebut kita tahu bagaimana perilaku dari webpack ketika ia dijalankan. Berikut penjelasan singkat dari kelima konsep tersebut:
  • Entry : Titik awal di mana webpack akan menganalisa berkas dan membentuk dependency graph.
  • Output : Berkas bundel yang dihasilkan dari berkas-berkas yang dianalisis webpack berdasarkan entry point.
  • Loaders :  Transformation tools pada webpack, yang akan memproses setiap berkas selain JavaScript atau JSON yang kita impor menjadi format yang dapat digunakan ke tahap produksi.
  • Plugin :  Digunakan untuk melakukan tugas seperti optimasi bundel, management aset dan sebagainya.
  • Mode : Kondisi yang digunakan webpack sebagai acuan optimasi apa saja yang harus diterapkan dalam melakukan tugasnya. Dalam mode kita dapat menetapkan nilai productiondevelopment ataupun none

Entry

Entry atau entry point merupakan modul pertama yang akan dianalisa oleh webpack ketika ia dijalankan. Melalui entry point inilah webpack akan membentuk dependency graph. Webpack akan mencari tahu modul lain yang digunakan pada entry point dan menggabungkannya menjadi satu static assets.
Pada webpack 4 standarnya nilai entry point akan ditempatkan pada ./src/index.js. Namun kita dapat menetapkan lokasi yang berbeda dengan mengatur properti entry pada berkas webpack configuration (webpack.config.js). Contohnya:

  1. module.exports = {

  2.   entry: './path/to/my/entry/file.js'

  3. };



Kode di atas merupakan cara cepat dalam penulisan properti entry. Sebenarnya entry dapat berupa objek seperti ini:

  1. module.exports = {

  2.   entry: {

  3.     main: './path/to/my/entry/file.js'

  4.   }

  5. };



Kita bisa memanfaatkan objek sebagai nilai entry ketika terdapat banyak entry point yang ingin kita tetapkan.

  1. module.exports = {

  2.   entry: {

  3.     app: './src/app.js',

  4.     adminApp: './src/adminApp.js'

  5.   }

  6. };



Output

Output merupakan salah satu properti yang terdapat pada webpack configuration. Properti ini berfungsi untuk memberitahu webpack di mana dan bagaimana lokasi static assets yang telah dibundel harus disimpan dan diberi nama. Standarnya lokasi penyimpanannya berada pada dist -> main.js. Lokasi dist merupakan lokasi standar untuk menyimpan berkas yang dihasilkan oleh webpack.
Kita dapat mengkonfigurasi bagian output ini melalui properti output pada webpack.config.js seperti contoh berikut ini:

  1. const path = require('path');

  2.  

  3. module.exports = {

  4.   entry: './path/to/my/entry/file.js',

  5.   output: {

  6.     path: path.resolve(__dirname, 'dist'),

  7.     filename: 'my-first-webpack.bundle.js'

  8.   }

  9. };



Pada contoh di atas, kita menggunakan output.filename dan output.path properties untuk memberitahu webpack penamaan dan lokasi static assets yang sudah dibundel. 
Pada contoh di atas juga kita dapat melihat modul path yang diimpor menggunakan Node.js module. 
Modul tersebut merupakan modul standar pada Node.js yang digunakan untuk memanipulasi lokasi berkas. Untuk memahami lebih dalam mengenai module path silakan cek  https://nodejs.org/api/path.html
Jika kita menetapkan lebih dari satu entry point, kita perlu menggunakan substitution untuk memastikan berkas yang dihasilkan webpack memiliki nama unik.

  1. module.exports = {

  2.   entry: {

  3.     app: './src/app.js',

  4.     search: './src/search.js'

  5.   },

  6.   output: {

  7.     filename: '[name].js',

  8.     path: __dirname + '/dist'

  9.   }

  10. };

  11.  

  12. // webpack akan menghasilkan: ./dist/app.js, ./dist/search.js



Properti output memiliki banyak fitur dalam proses konfigurasinya. 

Loaders

Dalam melaksanakan tugas, sejatinya Webpack hanya mengenali berkas JavaScript dan JSON. Namun melalui loaders webpack dapat memproses berkas berformat lain seperti css, sass, pug, jsx atau yang lainnya. Loaders merupakan sebuah transformation tools pada webpack yang akan memproses setiap berkas selain JavaScript atau JSON yang kita impor menjadi format yang dapat digunakan ke tahap produksi.
Jika pada build tools lain seperti Gulp atau Grunt, loaders ini seperti “task”. Task ini sangat membantu dalam menangani proses front-end building. Loader dapat mengubah berkas bahasa pemrograman lain seperti TypeScript ke JavaScript. Yang paling spesial dari loader ini kita dapat melakukan import berkas .css langsung pada entry point layaknya berkas JavaScript pada dependency graph.
202003131716233f57b6b8ca088c0223cd40f39b99af85.png

Kemampuan impor pada modul apapun (contohnya .css) merupakan fitur spesifik dari webpack yang mungkin tak akan kita jumpai pada module bundler atau task runner lain. Alhasil, kita dapat lebih leluasa lagi alias tak terbatas dengan tipe berkas dalam menggunakan module pada webpack.
Untuk menetapkan loaders kita gunakan properti module.rules pada webpack configuration (webpack.config.js). Di dalamnya terdapat dua high level properties yaitu test, dan use. Berikut penjelasan singkatnya:
  • Properti test merupakan tipe berkas yang akan ditransformasikan.
  • Properti use merupakan loader mana yang akan digunakan untuk mentransformasikan berkas tersebut.
Belum terbayang bagaimana penggunaannya? Berikut contoh konfigurasi dari properti loader:

  1. module.exports = {

  2.   module: {

  3.     rules: [

  4.       { test: /\.css$/, use: 'css-loader' }

  5.     ]

  6.   }

  7. };



Konfigurasi di atas memiliki properti module.rules dan menetapkan properti test dan use di dalamnya. Konfigurasi seperti ini layaknya kita memberitahu “Hey webpack compiler! Ketika Anda bertemu dengan berkas .css yang dihubungkan menggunakan import atau require statement, gunakanlah css-loader untuk mengubahnya sebelum membungkusnya ke dalam bundle”.
Banyak sekali loader yang dapat kita gunakan pada webpack configuration. Namun loader tersebut tidak disertakan langsung ketika kita menggunakan webpack. Jika kita ingin menggunakan loader katakanlah css-loader, maka kita perlu memasang package loader tersebut melalui npm.

  1. npm install css-loader --save-dev



Contoh sebelumnya merupakan cara ringkas ketika kita menetapkan loader agar mudah dibaca. Melalui module.rules sebenarnya kita dapat menetapkan banyak loader, namun dalam penulisannya kita perlu menetapkan loader tersebut secara eksplisit seperti ini:

  1. module.exports = {

  2.     module: {

  3.         rules: [

  4.             {

  5.                 test: /\.css$/,

  6.                 use: [

  7.                     {

  8.                         loader: "style-loader"

  9.                     },

  10.                     {

  11.                         loader: "css-loader"

  12.                     }

  13.                 ]

  14.             }

  15.         ]

  16.     }

  17. }



Dalam menuliskan banyak loader dalam satu rule, urutan deklarasi loader tersebut sangat berpengaruh. Loader akan tereksekusi dengan urutan dari bawah ke atas. Pada contoh di atas eksekusi akan dimulai dari css-loader, lalu dilanjutkan oleh style-loader.
Dengan menuliskan loader secara eksplisit seperti ini, kita juga dapat dengan mudah menambahkan konfigurasi pada loader yang digunakan melalui properti options. 
Contohnya:
  1. module.exports = {
  2.     module: {
  3.         rules: [
  4.             {
  5.                 test: /\.css$/,
  6.                 use: [
  7.                     {
  8.                         loader: "style-loader",
  9.                         options: {
  10.                             // memasukkan style dengan tag <style> di bawah dari element <body> 
  11.                             insert: "body"
  12.                         }
  13.                     },
  14.                     {
  15.                         loader: "css-loader"
  16.                     }
  17.                 ]
  18.             }
  19.         ]
  20.     }
  21. }

Untuk melihat loader apa saja yang dapat kita manfaatkan pada webpack dan konfigurasi apa saja yang dapat diterapkan pada masing-masing loadernya, kita dapat melihatnya secara lengkap pada dokumentasi resmi webpack melalui tautan berikut: Webpack Loaders Documentation.

Plugin

Plugin pada webpack digunakan untuk melakukan tugas seperti optimasi bundel, management aset dan sebagainya. Dengan adanya plugin ini, webpack menjadi lebih fleksibel. Plugin merupakan tulang punggung dari webpack. Bahkan webpack sendiri dibangun menggunakan sistem plugin yang sama seperti yang kita lakukan pada webpack configuration.
Webpack Plugin merupakan sebuah JavaScript objek yang dibangun menggunakan JavaScript class yang di dalamnya terdapat method apply dengan satu argument bernama compiler. Kita dapat membuat webpack plugin sederhana dengan cara seperti ini: 

  1. const pluginName = 'ConsoleLogOnBuildWebpackPlugin';

  2.  

  3.  

  4. class ConsoleLogOnBuildWebpackPlugin {

  5.   constructor(options) {

  6.     this.options = options;

  7.   }

  8.  

  9.  

  10.   apply(compiler) {

  11.     compiler.hooks.run.tap(pluginName, compilation => {

  12.       console.log(this.options.message);

  13.     });

  14.   }

  15. }

  16.  

  17.  

  18. module.exports = ConsoleLogOnBuildWebpackPlugin;


Ketika kita menggunakan plugin tersebut pada webpack configuration, ia akan mencetak nilai this.options.message pada console ketika proses build pada webpack berjalan. 
Untuk saat ini jangan terfokus pada cara membuat plugin di webpack. Alih-alih, fokuslah pada bagaimana ia digunakan pada webpack configuration. 
Karena plugin merupakan objek dan kita mungkin menyimpan konfigurasi ketika ia dibuat, maka dalam membuat objek plugin kita perlu menggunakan keyword new seperti ini:
  1. const ConsoleLogOnBuildWebpackPlugin = require("./console-log-on-build-webpack-plugin.js");
  2.  
  3. module.exports = {
  4.     plugins: [
  5.     new ConsoleLogOnBuildWebpackPlugin({
  6.         message: "The webpack build process is starting!"
  7.     })
  8.     ]
  9. }

Banyak plugin baik standar webpack atau pihak ketiga yang dapat kita manfaatkan pada webpack. 
Karena itulah kita tidak perlu fokus pada bagaimana membuat plugin. Untuk menggunakan plugin standar webpack, kita dapat mengaksesnya melalui objek webpack seperti ini:

  1. const webpack = require("webpack"); // dibutuhkan untuk mengakses built-in plugins

  2.  

  3. module.exports = {

  4.     plugins: [

  5.     new webpack.ProgressPlugin()

  6.     ]

  7. }



Namun, untuk menggunakan beberapa plugin (di luar plugin standar yang disediakan) kita perlu memasangnya terlebih dahulu melalui npm. 
Contohnya plugin yang banyak digunakan untuk membuat berkas HTML pada webpack adalah html-webpack-plugin. Untuk memasangnya kita gunakan perintah berikut:

  1. npm install html-webpack-plugin --save-dev



Setelah memasangnya kita dapat menggunakannya pada webpack configuration seperti ini:

  1. const HtmlWebpackPlugin = require('html-webpack-plugin'); //dipasang via npm

  2.  

  3. module.exports = {

  4.   plugins: [

  5.         new HtmlWebpackPlugin({

  6.             template: "./src/index.html",

  7.             filename: "index.html"

  8.         })

  9.     ]

  10. };



Pada contoh di atas, melalui html-webpack-plugin webpack akan menghasilkan berkas HTML untuk proyek kita dan memasukkan berkas yang sudah dibundel

Mode

mode merupakan salah satu properti yang terdapat pada webpack configuration. Dengan memberikan mode dengan nilai developmentproduction atau none, kita dapat melakukan optimasi pada webpack berdasarkan mode yang kita kehendaki. Jika kita tidak menetapkan nilai pada properti mode, secara default akan bernilai production.

  1. module.exports = {

  2.     mode: 'production'

  3. };



Nilai mode juga dapat kita tetapkan melalui CLI argument seperti berikut:

  1. webpack --mode development



Kita dapat melakukan optimasi pada webpack berdasarkan mode yang kita kehendaki karena tiap properti pada webpack configuration menyesuaikan pada modenya. 
Misalkan, jika kita menggunakan mode development, kita dapat menggunakan properti devtoolcache, atau properti development lainnya pada webpack configuration.

  1. module.export = {

  2.     mode: 'development',

  3.     devtool: 'eval',

  4.     cache: 'true'

  5. }



Properti devtool atau cache tentu tidak dapat kita gunakan dalam mode production, tetapi kita dapat memanfaatkan properti-properti yang terdapat pada production
Begitu juga ketika kita menetapkan mode none. Untuk lebih lengkapnya, properti apa saja yang dapat kita manfaatkan di masing-masing modenya, silakan cek tautan berikut: Webpack Configuration Mode.
Jika kita ingin mengubah perilaku webpack berdasarkan nilai mode di dalam webpack.config.js, kita fungsi alih-alih objek.
  1. const config = {
  2.   entry: './app.js'
  3.   //...
  4. };
  5.  
  6. module.exports = (env, argv) => {
  7.  
  8.   if (argv.mode === 'development') {
  9.     config.devtool = 'source-map';
  10.   }
  11.  
  12.   if (argv.mode === 'production') {
  13.     //...
  14.   }
  15.  
  16.   return config;
  17. };

Atau kita dapat menggunakan flag --config pada scripts berkas package.json untuk menetapkan berkas webpack configuration yang berbeda pada tiap modenya.

  1. "scripts": {

  2.     "build:prod": "webpack --config webpack.prod.js",

  3.     "build:dev": "webpack --config webpack.dev.js",

  4. }


Using Webpack

Setelah mengetahui apa itu webpack dan seperti apa core concepts-nya, mungkin sebagian dari kita masih bingung jika belum mencobanya langsung. Untuk itu mari kita coba terapkan webpack pada proyek WebClock yang sudah kita buat sebelumnya. Karena pada proyek tersebut kita masih menggunakan tag <script> dalam menggunakan package yang terpasang menggunakan npm.
Sebelum melanjutkan ke materi selanjutnya. Pastikan Anda ikuti instruksi pada modul Node Package Manager hingga proyek WebClock menghadirkan tampilan seperti ini:
20200313192946751f2abb46ff53418e64c03942773582.gif
Belum ada tampilan demikian? Yuk baca kembali modul pada Node Package Manager dan ikuti instruksi di sana. Untuk Anda yang sudah sampai tahap tersebut, ayo kita gunakan webpack mulai dari cara memasangnya.

Installing Webpack

Memasang webpack pada proyek kita sama seperti kita memasang package JQuery atau Moment.js. Namun webpack ini dipasang pada devDependencies karena sejatinya ia hanya digunakan selama proses pengembangan saja. 
Untuk memasang webpack silakan buka proyek Anda. Pada terminal kita tuliskan perintah berikut:

  1. npm install webpack --save-dev

  2. npm install webpack-cli --save-dev


Atau kita dapat menyingkat perintah tersebut dalam penulisan satu baris seperti ini:

  1. npm install webpack webpack-cli --save-dev


Setelah berhasil memasang package webpack dan webpack-cli, maka kita dapat melihat kedua package tersebut pada devDependencies di berkas package.json.
20200313193203eb8ab066c7cf5c7d36ee34ab304ee6be.png
Mengapa kita membutuhkan dua package dalam memasang webpack? Apa fungsi package webpack dan webpack-cli
Package webpack merupakan package inti dari webpack itu sendiri. Sedangkan package webpack-cli merupakan package yang digunakan untuk membantu kita menjalankan webpack melalui sebuah perintah (Command Line Interface). 
Pada CLI juga kita dapat memberikan argumen seperti menetapkan berkas webpack config, atau mode dalam proses build.
Untuk menjalankan webpack kita perlu menambahkan script dengan perintah webpack pada package.json seperti ini:

  1. "scripts": {

  2.     "test": "echo \"Error: no test specified\" && exit 1",

  3.     "start": "http-server .",

  4.     "build": "webpack"

  5. },



Kita bisa menghapus script yang lainnya karena sudah tidak akan kita gunakan lagi. Sehingga sekarang berkas package.json akan tampak seperti ini:

  1. {

  2.   "name": "webclock",

  3.   "version": "1.0.0",

  4.   "description": "",

  5.   "main": "index.js",

  6.   "scripts": {

  7.     "build": "webpack"

  8.   },

  9.   "author": "",

  10.   "license": "ISC",

  11.   "dependencies": {

  12.     "jquery": "^3.4.1",

  13.     "moment": "^2.24.0"

  14.   },

  15.   "devDependencies": {

  16.     "webpack": "^4.41.6",

  17.     "webpack-cli": "^3.3.11"

  18.   }

  19. }



Lalu untuk menjalankan script build, kita gunakan perintah berikut:

  1. npm run build



Namun untuk saat ini jika menjalankan script build akan terjadi eror seperti ini:
202003131934278ded0ab441e5a0bdb11a0e5f88fcfe66.png
Dari pesan berikut, kita dapat menyimpulkan bahwa ketika kita tidak/belum menetapkan webpack configuration, nilai entry standarnya akan berlokasi pada src -> index.js

  1. ERROR in Entry module not found: Error: Can't resolve './src' in 'C:\Users\Dicoding\Desktop\WebClock'


Untuk itu mari kita sesuaikan dengan membuat folder src dan memindahkan index.js pada folder tersebut. Sehingga struktur proyeknya akan tampak seperti ini:
20200313193530ff33d34b4c276d7f0165d30a79a5179a.png
Lalu coba kita jalankan kembali script build, maka hasilnya akan tampak seperti ini:
20200314052546ad48eb36384caa7e498addc98e6ba500.png
Pada struktur proyek kita juga terlihat terdapat folder baru dengan nama dist, di mana di dalamnya terdapat berkas main.js yang merupakan hasil bundel dari entry point src -> index.js
Jika kita buka berkas tersebut, akan tampil banyak kode yang sulit kita baca. Jangan khawatir mengenai kode yang dihasilkan webpack itu. Namun jika dilihat pada akhir kodenya, kita akan menemukan kode asli yang kita tulis.
20200313193627744f50b9834d39a2b1709b03eebfa5d1.gif
Karena kita sudah menggunakan webpack untuk membundel module. Kita dapat menggunakan perintah import pada src -> index.js dalam menggunakan package npm.

  1. import $ from "jquery";

  2. import moment from "moment";

  3.  

  4. const displayTime = () => {

  5.     moment.locale("id");

  6.     $(".time").text(moment().format("LTS"));

  7.     $(".date").text(moment().format("LL"));

  8. };

  9.  

  10. const updateTime = () => {

  11.     displayTime();

  12.     setTimeout(updateTime, 1000)

  13. };

  14.  

  15. updateTime();



Kemudian pada index.html, kita dapat menggantikan seluruh tag <script> yang ada dengan satu tag <script> yang ditujukan pada dist -> main.js.

  1. <!DOCTYPE html>

  2. <html>

  3.     <head>

  4.         <title>Clock Web</title>

  5.         <link rel="stylesheet" href="style.css">

  6.     </head>

  7.     <body>

  8.         <div class="clock">

  9.             <span class="time"></span>

  10.             <span class="date"></span>

  11.         </div>

  12.         <script src="./dist/main.js"></script>

  13.     </body>

  14. </html>



Lalu kita build ulang proyek dengan menjalankan perintah:

  1. npm run build



Setelah build selesai dan menghasilkan berkas dist -> main.js yang baru, proyek WebClock seharusnya sudah bisa berjalan dengan baik ketika kita membuka berkas index.html.
20200313193821f67bcef3c951b5caf7555647b17fd05b.png
Langkah dari materi ini bisa Anda temukan juga pada repository berikut:
https://github.com/dicodingacademy/a163-bfwd-labs/tree/205-webclock-installing-webpack

Creating configuration files

Sebelumnya kita menggunakan webpack dengan zero configuration. Apa artinya? Kita dapat menggunakan webpack tanpa membuat berkas webpack configuration sama sekali. Zero configuration ini fitur baru dari webpack 4. Namun kekurangan dalam zero configuration adalah kita tidak dapat menyesuaikan konfigurasi yang kita inginkan ketika menggunakan webpack. Katakanlah jika kita perlu menggunakan sebuah loader atau plugin, tentu dengan zero configuration kita tidak dapat menggunakannya.
Kita dapat membuat berkas webpack configuration dengan membuat berkas JavaScript baru dengan nama webpack.config.js pada root folder proyek kita.
202003131940148f638bc852c2ddab2f771515a65338b0.png
Nama berkas tersebut merupakan nama standar bagi berkas webpack configuration. Kita dapat menetapkan nama lain sesuka kita namun kita perlu menambahkan argument --config pada webpack CLI. Kita akan mencoba hal ini nanti. Saat ini kita fokus dulu bagaimana cara menuliskan sintaks pada berkas webpack configuration.
Pada materi sebelumnya kita sudah mengenal konsep inti dari webpack ini. Ada entryoutputloaderplugins dan mode. Kelima konsep inti tersebut dapat menentukan perilaku webpack dalam melaksanakan tugasnya. Untuk konfigurasi awal, kita tetapkan terlebih dahulu entry dan output pada webpack configuration. Caranya dengan tambahkan kode berikut pada berkas webpack.config.js.

  1. const path = require("path");

  2.  

  3. module.exports = {

  4.     entry: "./src/index.js",

  5.     output: {

  6.         path: path.resolve(__dirname, "dist"),

  7.         filename: "bundle.js"

  8.     }

  9. }


Pada nilai entry walaupun kita menetapkannya namun tidak ada nilai yang berbeda seperti nilai standar yaitu src -> index.js. Namun pada nilai output, kita mengubah penamaan berkas hasil bundel dari main.js (nilai standar) menjadi bundle.js. Sehingga ketika kita jalankan kembali script build.

  1. npm run build


Maka akan terdapat berkas bundel baru bernama bundle.js.
2020031319450425966a4f5f052bd524adcdefcecb82a3.png
Namun kita juga masih dapat melihat berkas main.js yang merupakan berkas lama hasil proses build sebelumnya. Kita dapat menghapusnya karena sudah tidak digunakan lagi. Namun jangan lupa mengubah target berkas JavaScript yang dilampirkan pada index.html menjadi bundle.js.

  1. <!DOCTYPE html>

  2. <html>

  3.     <head>

  4.         <title>Clock Web</title>

  5.         <link rel="stylesheet" href="style.css">

  6.     </head>

  7.     <body>

  8.         <div class="clock">

  9.             <span class="time"></span>

  10.             <span class="date"></span>

  11.         </div>

  12.         <script src="./dist/bundle.js"></script>

  13.     </body>

  14. </html>


Jika kita membuka index.html maka akan tampil hasil yang sama seperti sebelumnya. Karena memang kita tidak melakukan apapun selain mengubah nama hasil bundel dari main.js (nilai standar) menjadi bundle.js.
Pada saat proses bundle, coba kita lihat pada Terminal. Terdapat warning yang menunjukkan bahwa kita tidak menetapkan mode pada berkas webpack configuration.
20200313194640a7040e4ef237e1dc7852c1e0a379a595.png
Jika kita tidak menetapkan nilai pada properti mode maka nilai standar akan diterapkan, yakni nilai production. Namun daripada kita membiarkan properti mode ini tidak memiliki nilai, sebaiknya kita tetapkan saja nilai modenya. Untuk saat ini, kita tetapkan properti mode dengan nilai production.

  1. const path = require("path");

  2.  

  3. module.exports = {

  4.     entry: "./src/index.js",

  5.     output: {

  6.         path: path.resolve(__dirname, "dist"),

  7.         filename: "bundle.js"

  8.     },

  9.     mode: "production"

  10. }


Lalu coba jalankan kembali script build. Maka warning mengenai properti mode tidak akan muncul pada Terminal saat proses build berjalan.
“Sebenarnya kita juga dapat melihat warning lain yang menunjukkan ukuran bundle.js sudah melampaui batas. Kita bisa lihat sendiri dengan membuka berkas bundle.js. Di sana kita akan menemukan banyak sekali kode yang dihasilkan dibandingkan dengan sebelumnya. 
Hal ini disebabkan kode yang kita tulis memiliki ketergantungan (dependencies) terhadap package JQuery dan Moment. Sehingga package tersebut perlu dibundel juga pada berkas bundle.js. karena itulah berkas bundle.js menjadi bengkak ukurannya. 
Ini merupakan salah satu alasan mengapa sebaiknya kita hindari penggunaan package pihak ketiga yang kita bawa hingga tingkat production. Membengkaknya berkas bundle.js, tentu akan berdampak terhadap performa web yang kita bangun nantinya.”

Langkah dari solution ini bisa Anda temukan juga pada repository berikut:
https://github.com/dicodingacademy/a163-bfwd-labs/tree/206-webclock-webpack-configuration-files

Using Loader

Pada penjelasan core concepts kita sudah tahu bahwa dengan loader, webpack dapat memproses berkas selain JavaScript. Dengan adanya loader kita dapat menggunakan CSS sebagai modul dan ikut terbundel bersama berkas bundle.js. Sehingga kita tidak perlu lagi menerapkan tag <link> pada index.html.

Style and CSS Loader

Untuk menggunakan CSS modul pada webpack, kita membutuhkan dua buah loader. Yang pertama css-loader dan yang kedua style-loadercss-loader merupakan loader untuk memproses berkas dengan format .css. Sedangkan style-loader merupakan loader yang digunakan untuk membuat styling dapat diterapkan secara modular dengan menggunakan import statement. 
Untuk menggunakan kedua loader tersebut, langkah pertama adalah memasangnya melalui npm dengan perintah: 

  1. npm install style-loader css-loader --save-dev



Setelah berhasil, pada berkas webpack.config.js kita tambahkan properti module.rules dan isikan nilai loader seperti ini:
  1. const path = require("path");
  2.  
  3. module.exports = {
  4.     entry: "./src/index.js",
  5.     output: {
  6.         path: path.resolve(__dirname, "dist"),
  7.         filename: "bundle.js"
  8.     },
  9.     mode: "production",
  10.     module: {
  11.         rules: [
  12.             {
  13.                 test: /\.css$/,
  14.                 use: [
  15.                     {
  16.                         loader: "style-loader"
  17.                     },
  18.                     {
  19.                         loader: "css-loader"
  20.                     }
  21.                 ]
  22.             }
  23.         ]
  24.     }
  25. }

Setelah menambahkan loader pada webpack.config.js, sekarang kita dapat melakukan impor berkas CSS menggunakan import statement layaknya berkas JavaScript.
Namun sebelum itu, pindahkan terlebih dahulu berkas style.css agar lebih rapi ke dalam direktori baru dengan lokasi src -> style -> style.css. Sehingga struktur proyek akan tampak seperti ini:
20200313195233801f7eecca052bdc6bfed86c4136ea86.png
Lalu pada berkas index.js, lakukan impor berkas style.css pada awal baris kodenya.

  1. import "./style/style.css";


Maka keseluruhan kode pada index.js akan tampak seperti ini:

  1. import "./style/style.css";

  2. import $ from "jquery";

  3. import moment from "moment";

  4.  

  5. const displayTime = () => {

  6.     moment.locale("id");

  7.     $(".time").text(moment().format("LTS"));

  8.     $(".date").text(moment().format("LL"));

  9. };

  10.  

  11. const updateTime = () => {

  12.     displayTime();

  13.     setTimeout(updateTime, 1000)

  14. };

  15.  

  16. updateTime();


Dengan begitu kita tidak membutuhkan lagi tag <link> pada index.html dalam melampirkan stylesheet pada berkas style.css. Kita hapus tag <link> berikut:

  1. <link rel="stylesheet" href="style.css">


Sehingga keseluruhan kode pada index.html akan tampak seperti ini:

  1. <!DOCTYPE html>

  2. <html>

  3.     <head>

  4.         <title>Clock Web</title>

  5.     </head>

  6.     <body>

  7.         <div class="clock">

  8.             <span class="time"></span>

  9.             <span class="date"></span>

  10.         </div>

  11.         <script src="./dist/bundle.js"></script>

  12.     </body>

  13. </html>


Setelah itu coba jalankan kembali script build untuk menghasilkan berkas bundle.js yang baru dan buka index.html pada browser. Seharusnya proyek WebClock menampilkan hasil yang sama seperti sebelumnya.
202003131956308d12987bb21047da2fbf283a93369895.gif
Selamat! Itu artinya, Anda berhasil menerapkan styling dengan cara modular menggunakan webpack loader. Jika Anda lihat pada berkas bundle.js saat ini, kita dapat menemukan styling yang dituliskan. 
2020031319565824078682376dded444e3b638090ac715.png
Hal inilah mengapa styling dapat diterapkan tanpa harus menggunakan tag <link> pada berkas index.html.

Babel Loader

Kita sudah berhasil menggunakan dan merasakan manfaat dari style-loader dan css-loader. Namun sebenarnya masih banyak loader lain yang tak kalah pentingnya untuk diterapkan pada webpack. Salah satunya adalah babel-loader
2020031319583407bf63e74fd402a5583504377dfd8829.png
Mungkin sebagian dari kita sudah ada yang mengetahui apa itu babel atau babel.js? Babel merupakan sebuah transpiler yang bertugas untuk mengubah sintaks JavaScript modern (ES6+) menjadi sintaks yang dapat didukung penuh oleh seluruh browser.
JavaScript merupakan bahasa pemrograman yang berkembang sangat pesat. Komunitasnya besar, dan tiap tahun selalu terdapat versi yang baru. Namun perkembangan yang pesat tadi ternyata membutuhkan waktu yang lama untuk diadaptasi oleh browser atau Node.js. Lalu jika kita ingin mencoba sintaks terbaru di JavaScript apakah kita perlu menunggu hingga seluruh browser berhasil mengadaptasi pembaharuan tersebut? Tentu tidak! 
Dengan babel Anda dapat menuliskan sintaks JavaScript versi terbaru tanpa khawatir memikirkan dukungan pada browser. Karena babel akan mengubah sintaks yang kita tuliskan menjadi kode yang dapat diterima browser.
Jika Anda penasaran bagaimana cara babel bekerja, babel menyediakan sebuah playground yang dapat kita manfaatkan untuk mengubah sintaks JavaScript modern (ES6+) menjadi sintaks lama. Untuk mencobanya, silakan Anda buka tautan berikut: https://babeljs.io/repl.
20200313195932ff6b88f0352e20c9c08f27fd89aff700.png
Pada playground tersebut kita juga dapat memilih preset yang kita inginkan. Secara default preset akan mengarah ES2015 (ES6).
Anda sudah tahu  sekilas mengenai babel. Nah pada webpack kita juga dapat menggunakan babel dalam bentuk loader. Walaupun webpack secara standarnya dapat memproses berkas JavaScript tanpa perlu bantuan loader, namun proses tersebut tidak mengubah sintaks yang kita tuliskan. Artinya jika kita menuliskan sintaks JavaScript modern, maka kita akan menemukannya juga pada berkas bundle.js.
2020031320001286d0cce40a7f1f8ac22836dcbab4867b.png
Walaupun saat ini Google Chrome dan Mozilla Firefox sudah mendukung penulisan sintaks ES6, namun setidaknya kita perlu sedikit peduli terhadap dukungan browser lama seperti Internet Explorer atau browser versi lama lainnya.
Untuk menggunakan babel pada webpack sebagai loader, kita perlu memasang tiga package menggunakan npm pada devDependencies
Yang pertama package @babel/core, yang kedua babel-loader, dan yang ketiga @babel/preset-env.

  1. npm install @babel/core babel-loader @babel/preset-env --save-dev



Package @babel/core merupakan package inti yang harus dipasang ketika kita hendak menggunakan babel, baik pada webpack maupun tools yang lain.
Package babel-loader merupakan package yang diperlukan untuk menggunakan babel sebagai loader pada webpack.
Yang terakhir package @babel/preset-env merupakan package preset yang akan kita gunakan untuk membantu babel-loader dalam melakukan tugasnya. @babel/preset-env merupakan preset cerdas yang memungkinkan kita menggunakan sintaks JavaScript terbaru tanpa menetapkan secara spesifik sintaks JavaScript versi apa yang kita gunakan.
Berkas package.json akan tampak seperti ini setelah memasang ketiga package tersebut:
  1. {
  2.   "name": "webclock",
  3.   "version": "1.0.0",
  4.   "description": "",
  5.   "main": "index.js",
  6.   "scripts": {
  7.     "build": "webpack"
  8.   },
  9.   "author": "",
  10.   "license": "ISC",
  11.   "dependencies": {
  12.     "jquery": "^3.4.1",
  13.     "moment": "^2.24.0"
  14.   },
  15.   "devDependencies": {
  16.     "@babel/core": "^7.8.4",
  17.     "@babel/preset-env": "^7.8.4",
  18.     "babel-loader": "^8.0.6",
  19.     "css-loader": "^3.4.2",
  20.     "style-loader": "^1.1.3",
  21.     "webpack": "^4.41.6",
  22.     "webpack-cli": "^3.3.11"
  23.   }
  24. }

Setelah berhasil memasang ketiga package tersebut, langkah selanjutnya kita dapat gunakan babel-loader dan preset-nya pada webpack configuration.
  1. const path = require("path");
  2.  
  3. module.exports = {
  4.     entry: "./src/index.js",
  5.     output: {
  6.         path: path.resolve(__dirname, "dist"),
  7.         filename: "bundle.js"
  8.     },
  9.     mode: "production",
  10.     module: {
  11.         rules: [
  12.             /* style and css loader */
  13.             {
  14.                 test: /\.css$/,
  15.                 use: [
  16.                     {
  17.                         loader: "style-loader"
  18.                     },
  19.                     {
  20.                         loader: "css-loader"
  21.                     }
  22.                 ]
  23.             },
  24.             /* babel loader */
  25.             {
  26.                 test: /\.js$/,
  27.                 exclude: "/node_modules/",
  28.                 use: [
  29.                     {
  30.                         loader: "babel-loader",
  31.                         options: {
  32.                             presets: ["@babel/preset-env"]
  33.                         }
  34.                     }
  35.                 ]
  36.             }
  37.         ]
  38.     }
  39. }

Ketika menerapkan rule untuk berkas .js, jangan lupa untuk menetapkan properti exclude dengan nilai “/node_modules/”. Apa artinya? Dengan menetapkan properti exclude itu berarti kita mengecualikan webpack untuk memproses berkas .js yang berada pada folder “node_modules”. Hal ini dapat meminimalisir proses yang tidak diperlukan, sehingga mempercepat proses build pada proyek kita.  
Lalu pada penerapan babel-loader juga kita menggunakan properti options dengan menetapkan properti presets di dalamnya. Pada properti presets kita tetapkan preset (dalam bentuk array literas) yang sudah kita pasang menggunakan npm, yaitu @babel/preset-env.
Setelah menggunakan babel loader pada webpack configuration, mari kita coba build dan buka kembali berkas bundle.js. Maka kode yang kita tuliskan dalam ES6 akan diubah dalam sintaks yang dapat diterima oleh seluruh browser.
20200313200507f7a720e39de819c62a15f1be147aa62e.png
Bahkan pada berkas bundle tersebut dipastikan sudah tidak terdapat lagi sintaks yang dituliskan menggunakan ES6.
20200313200535f035aab9b99622b9e95be3f0d98fc827.png
Namun walaupun sintaksnya sudah diubah, proyek akan tetap berjalan normal seperti biasanya.
Langkah dari materi ini bisa Anda temukan juga pada repository berikut:
https://github.com/dicodingacademy/a163-bfwd-labs/tree/207-webclock-webpack-using-loader

Using Plugins

Ketika membuat web application tentunya kita membutuhkan minimal satu berkas HTML yang biasanya dinamai dengan index.html. Dengan menambahkan plugin HtmlWebpackPlugin, Webpack dapat membuatkan berkas HTML dan memasukkan script hasil bundel pada berkas HTML yang dibuat secara otomatis. HtmlWebpackPlugin juga mendukung templating dan penggunaannya sangat dapat dikonfigurasi.
Untuk menggunakan html-webpack-plugin, langkah pertama adalah memasang package html-webpack-plugin pada devDependencies menggunakan npm.

  1. npm install html-webpack-plugin --save-dev


Setelah memasangnya, pada berkas webpack.config.js lakukan impor package html-webpack-plugin sebagai objek dengan nama HtmlWebpackPlugin.

  1. const path = require("path");

  2. const HtmlWebpackPlugin = require("html-webpack-plugin");

  3.  

  4. module.exports = ....


Selanjutnya di dalam mode.exports mari tambahkan properti plugins dengan nilai berikut:

  1. const path = require("path");

  2. const HtmlWebpackPlugin = require("html-webpack-plugin");

  3.  

  4. module.exports = {

  5.    ......,

  6.     /* plugin */

  7.     plugins: [

  8.         /* HTML Webpack Plugin */

  9.         new HtmlWebpackPlugin({

  10.             template: "./index.html",

  11.             filename: "index.html"

  12.         })

  13.     ]

  14. }


Di dalam penggunaan plugin HtmlWebpackPlugin Anda dapat menentukan konfigurasi di dalam konstruktornya. Pada contoh kode di atas Anda menetapkan konfigurasi untuk template dan filename. Template di sana merupakan berkas rujukan bagi pembuatan berkas HTML yang dihasilkan HtmlWebpackPlugin. Lalu nilai dari properti filename akan digunakan sebagai penamaan berkas HTML yang akan dihasilkan nanti.
Mungkin contoh kode di atas membuat Anda sedikit bingung karena baik template dan filename kita menetapkan nama yang sama (index.html). Padahal sebenarnya Anda dapat menetapkan nama berkasnya sesuai keinginan. Untuk itu, mari ubah penamaan dan bedakan lokasi index.html yang ada sekarang menjadi  src -> template.html
Dengan begitu struktur proyek akan tampak seperti ini:
20200313201015db1016497427c5f6f480d7ffa0e21690.png
Lalu ubah juga lokasi template pada webpack configuration menjadi:

  1. const path = require("path");

  2. const HtmlWebpackPlugin = require("html-webpack-plugin");

  3.  

  4. module.exports = {

  5.     ......,

  6.     /* plugin */

  7.     plugins: [

  8.         /* HTML Webpack Plugin */

  9.         new HtmlWebpackPlugin({

  10.             template: "./src/template.html",

  11.             filename: "index.html"

  12.         })

  13.     ]

  14. }



Oh ya, karena HtmlWebpackPlugin secara otomatis akan memasukan output script bundle pada berkas HTML yang dihasilkannya, kita tidak perlu menetapkan tag <script> secara manual pada berkas template.html. Dengan begitu kita dapat menghapusnya.

  1. <!DOCTYPE html>

  2. <html>

  3.     <head>

  4.         <title>Clock Web</title>

  5.     </head>

  6.     <body>

  7.         <div class="clock">

  8.             <span class="time"></span>

  9.             <span class="date"></span>

  10.         </div>

  11.     </body>

  12. </html>



Setelah menambahkan HtmlWebpackPlugin pada webpack configuration, seluruh kode pada berkas webpack.config.js akan tampak seperti ini:
  1. const path = require("path");
  2. const HtmlWebpackPlugin = require("html-webpack-plugin");
  3.  
  4. module.exports = {
  5.     entry: "./src/index.js",
  6.     output: {
  7.         path: path.resolve(__dirname, "dist"),
  8.         filename: "bundle.js"
  9.     },
  10.     mode: "production",
  11.     module: {
  12.         rules: [
  13.             /* style and css loader */
  14.             {
  15.                 test: /\.css$/,
  16.                 use: [
  17.                     {
  18.                         loader: "style-loader"
  19.                     },
  20.                     {
  21.                         loader: "css-loader"
  22.                     }
  23.                 ]
  24.             },
  25.             /* babel loader */
  26.             {
  27.                 test: /\.js$/,
  28.                 exclude: "/node_modules/",
  29.                 use: [
  30.                     {
  31.                         loader: "babel-loader",
  32.                         options: {
  33.                             presets: ["@babel/preset-env"]
  34.                         }
  35.                     }
  36.                 ]
  37.             }
  38.         ]
  39.     },
  40.     /* plugin */
  41.     plugins: [
  42.         /* HTML Webpack Plugin */
  43.         new HtmlWebpackPlugin({
  44.             template: "./src/template.html",
  45.             filename: "index.html"
  46.         })
  47.     ]
  48. }

Coba build kembali proyek dengan menjalankan script build, maka folder dist akan menghasilkan berkas index.html.
2020031320123065a5a75f727db290877cd7b6d99ccc2e.png
Sekarang seluruh komponen yang dibutuhkan untuk menjalankan proyek WebClock sudah terdapat pada folder dist. Untuk menjalankan proyek WebClock kita cukup membuka berkas index.html pada browser. Bahkan sekarang kita bisa mengunggah aplikasi WebClock pada internet dengan men-deploy seluruh berkas yang terdapat pada folder dist. Dengan kata lain, seluruh berkas yang dibutuhkan untuk tahap production sudah terdapat di dalam folder dist.
Selamat! Sejauh ini kita sudah berhasil menggunakan webpack untuk membantu pengembangan aplikasi web hingga ke tahap production. Namun pembahasan webpack belum berakhir di sini yah. Pada materi selanjutnya kita akan belajar fitur lain yang tak kalah menarik yaitu Webpack Dev Server. Siap? Let’s go!
Langkah dari materi ini bisa Anda temukan juga pada repository berikut: https://github.com/dicodingacademy/a163-bfwd-labs/tree/208-webclock-webpack-using-plugin

Webpack Dev Server

Saat ini setiap terjadi perubahan kode pada proyek, Anda perlu melakukan build ulang untuk melihat hasilnya. Tak peduli perubahan tersebut bersifat  mayor ataupun hanya sekadar ganti warna saja. Karena untuk melihat perubahan terbaru kita juga perlu memperbaharui berkas bundle.js. Tentu sangat merepotkan bukan?
Untunglah webpack menyediakan fitur live-reloading yang dapat mempercepat proses pengembangan menggunakan Webpack Dev Server. Dengan ini kita dapat melihat perubahan secara langsung tanpa harus menjalankan ulang perintah build.
Untuk menggunakan Webpack Dev Server langkah pertama adalah kita pasang package webpack-dev-server pada devDependencies menggunakan npm.

  1. npm install webpack-dev-server --save-dev


Setelah berhasil memasangnya, kita tambahkan script start-dev dengan perintah “webpack-dev-server” pada package.json.

  1. "scripts": {

  2.     "build": "webpack",

  3.     "start-dev": "webpack-dev-server"

  4. }


Mari kita jalankan script start-dev dengan perintah:

  1. npm run start-dev


Setelah menjalankan perintah di atas, pada terminal kita dapat melihat alamat localhost:8080. Alamat tersebut digunakan untuk melihat proyek yang sedang kita kembangkan pada browser.
202003132019248725f53a4bca9fccd53a300da521d958.png
Webpack Dev Server secara standar memiliki fitur live-reloading. Artinya setiap terjadi perubahan terhadap assets yang digunakan (HTML, CSS, atau JS) dan menyimpan perubahannya (save), ia akan melakukan melakukan proses compiling ulang dan menampilkan hasil perubahan langsung pada browser.
20200313202124bafcb1767b5e2c4612e445a32bab8535.gif
Namun jika kita lihat proses compiling memakan waktu yang cukup lama bukan? Pada contoh gif di atas, butuh setidaknya 5 detik untuk Webpack Dev Server menampilkan perubahan terbaru pada browser. Mengapa bisa demikian?
Hal tersebut terjadi karena kita menggunakan mode production dalam menjalankan Webpack Dev Server. Ketika menggunakan mode production maka webpack melakukan bundling module seoptimal mungkin sehingga proses membutuhkan waktu lebih lama dibandingkan dengan mode development. Selain itu, pada webpack configuration kita menggunakan babel-loader. Proses compiling yang lama akan terasa lebih lama lagi karena kita harus melalui proses transpiling kode JavaScript melalui babel-loader
Solusinya, pisahkan webpack configuration untuk development dan production.
Untuk menghentikan service webpack-dev-server, gunakan kombinasi ctrl + c pada terminal yang digunakan. Ingatlahbahwa sebaiknya kita hentikan service webpack-dev-server setiap kali ingin melakukan perubahan pada berkas webpack configuration.

Langkah dari materi ini bisa Anda temukan juga pada repository berikut: https://github.com/dicodingacademy/a163-bfwd-labs/tree/209-webclock-webpack-dev-server

Configuration Environment

Tujuan dari development dan production memanglah berbeda. Pada tahap development webpack akan menerapkan konfigurasi yang selalu optimal untuk mempercepat proses perubahan pada browser (hot reloading). Sedangkan pada proses production kita ingin fokus terhadap optimasi bundling dan kompatibilitasnya pada browser. Karena perbedaan fokus tersebut sebaiknya kita memisahkan konfigurasi antara keduanya.
20200313202603b0a75a4a5caa86c71871610658933e74.png
Namun jika berpatokan pada bagan di atas, antara keduanya terdapat konfigurasi umum (common) seperti entryoutputstyle-loadercss-loader dan HtmlWebpackPlugin. Untuk menghindari penulisan berulang, kita dapat menggunakan tools yang bernama webpack-merge yang berfungsi untuk menggabungkan konfigurasi umum dengan konfigurasi unik tiap environment-nya.
2020031320274773a72ddcc2ce0672b38d5e54a9b9d640.png

Using webpack-merge

Untuk menggunakan webpack-merge langkah awal adalah dengan memasang package tersebut pada devDependencies menggunakan NPM.

  1. npm install webpack-merge --save-dev


Kemudian kita buat berkas webpack konfigurasi baru dengan nama webpack.common.js.
20200313202917357502a1b9a527cd74048d4af80fbaf7.png
Di dalam berkas tersebut kita tuliskan konfigurasi umum yang digunakan pada setiap environment baik itu production atau development.
  1. const path = require("path");
  2. const HtmlWebpackPlugin = require("html-webpack-plugin");
  3.  
  4. module.exports = {
  5.     entry: "./src/index.js",
  6.     output: {
  7.         path: path.resolve(__dirname, "dist"),
  8.         filename: "bundle.js"
  9.     },
  10.     module: {
  11.         rules: [
  12.             /* style and css loader */
  13.             {
  14.                 test: /\.css$/,
  15.                 use: [
  16.                     {
  17.                         loader: "style-loader"
  18.                     },
  19.                     {
  20.                         loader: "css-loader"
  21.                     }
  22.                 ]
  23.             }
  24.         ]
  25.     },
  26.     /* plugin */
  27.     plugins: [
  28.         /* HTML Webpack Plugin */
  29.         new HtmlWebpackPlugin({
  30.             template: "./src/template.html",
  31.             filename: "index.html"
  32.         })
  33.     ]
  34. }

Kemudian kita buat 2 (dua) berkas webpack configuration baru dengan nama webpack.prod.js dan webpack.dev.js.
202003132030400247cbd50837f2c5b60c75395d5384c1.png
Kemudian pada masing-masing berkasnya, tuliskan kode berikut:

  1. const merge = require("webpack-merge");

  2. const common = require("./webpack.common.js");

  3.  

  4.  

  5. module.exports = merge(common, {

  6.     mode: "production",

  7.     module: {

  8.         rules: [

  9.             /* babel loader */

  10.             {

  11.                 test: /\.js$/,

  12.                 exclude: "/node_modules/",

  13.                 use: [

  14.                     {

  15.                         loader: "babel-loader",

  16.                         options: {

  17.                             presets: ["@babel/preset-env"]

  18.                         }

  19.                     }

  20.                 ]

  21.             }

  22.         ]

  23.     }

  24. })



  1. const merge = require("webpack-merge");

  2. const common = require("./webpack.common.js"); 

  3.  

  4.  

  5. module.exports = merge(common, {

  6.     mode: "development",

  7. })



Di dalam berkas webpack.common.js kita sudah menetapkan nilai entryoutput beberapa loader, dan plugin yang nilainya digunakan pada kedua environment. Sehingga kita tidak perlu menetapkannya lagi pada masing-masing berkas konfigurasi environment-nya.
Perhatikan juga bahwa kita menggunakan merge() dari package webpack-merge, untuk memasukkan konfigurasi umum pada konfigurasi tiap environment-nya.

  1. module.exports = merge(common, )



Setelah menetapkan konfigurasi umum dan konfigurasi pada tiap environment, mari ubah perintah script build dan start-dev pada package.json menjadi seperti ini:

  1. "scripts": {

  2.     "build": "webpack --config webpack.prod.js",

  3.     "start-dev": "webpack-dev-server --config webpack.dev.js"

  4. }



Dengan menambahkan flag --config [config-files] pada script build dan start-dev, maka Anda dapat secara leluasa menghapus berkas webpack.config.js karena memang sudah tidak digunakan lagi. 
Sehingga pada proyek WebClock hanya terdapat 3 (tiga) berkas webpack configuration.
202003132035126bfffe874273fbdfcae56ed9370be089.png
Coba kita jalankan kembali script start-dev ya. Seharusnya fitur live-reloading akan berjalan lebih cepat.
20200313203633827ca43f7ab670daa8d217cc826e4f88.gif
Langkah dari materi ini bisa Anda temukan juga pada repository berikut: https://github.com/dicodingacademy/a163-bfwd-labs/tree/210-webclock-webpack-merge/WebClock

Solution: Menerapkan Webpack pada Club Finder

Apakah Anda sudah berhasil menerapkan Webpack pada proyek Club Finder? Jika belum Ayo kita lakukan bersama-sama!
Pertama silakan buka kembali proyek Club Finder pada text editor yang Anda gunakan.
202003132043087b138a829b8a1c586c572f10c0cfa57c.png
Kemudian buka terminal pada lokasi proyek Club Finder dan tuliskan perintah

  1. npm init


Kemudian isi pertanyaan yang diberikan sesuai keinginan Anda, atau Anda bisa memberikan nilai default di setiap pertanyaan dengan langsung menekan enter pada tiap pertanyaannya. Setelah proses tersebut selesai, maka akan menghasilkan berkas package.json pada root folder proyek Club Finder.

  1. {

  2.  "name": "clubfinder",

  3.  "version": "1.0.0",

  4.  "description": "",

  5.  "main": "app.js",

  6.  "scripts": {

  7.    "test": "echo \"Error: no test specified\" && exit 1"

  8.  },

  9.  "author": "",

  10.  "license": "ISC"

  11. }


Selanjutnya kita pasang package yang akan kita gunakan melalui NPM. Berikut daftar package yang akan digunakan:
  • @babel/core
  • @babel/preset-env
  • babel-loader
  • css-loader
  • html-loader
  • html-webpack-plugin
  • style-loader
  • webpack
  • webpack-cli
  • webpack-dev-server
  • webpack-merge
Pasanglah package tersebut pada devDependecies. Kita dapat melakukannya dengan satu perintah berikut:

  1. npm install @babel/core @babel/preset-env babel-loader css-loader html-loader html-webpack-plugin style-loader webpack webpack-cli webpack-dev-server webpack-merge --save-dev



Setelah menjalankan perintah di atas pada terminal, maka kita dapat melihat daftar package yang dipasang pada berkas package.json.
  1. {
  2.  "name": "clubfinder",
  3.  "version": "1.0.0",
  4.  "description": "",
  5.  "main": "app.js",
  6.  "scripts": {
  7.    "test": "echo \"Error: no test specified\" && exit 1"
  8.  },
  9.  "author": "",
  10.  "license": "ISC",
  11.  "devDependencies": {
  12.    "@babel/core": "^7.8.7",
  13.    "@babel/preset-env": "^7.8.7",
  14.    "babel-loader": "^8.0.6",
  15.    "css-loader": "^3.4.2",
  16.    "html-loader": "^0.5.5",
  17.    "html-webpack-plugin": "^3.2.0",
  18.    "style-loader": "^1.1.3",
  19.    "webpack": "^4.42.0",
  20.    "webpack-cli": "^3.3.11",
  21.    "webpack-dev-server": "^3.10.3",
  22.    "webpack-merge": "^4.2.2"
  23.  }
  24. }

Selanjutnya kita buat tiga berkas webpack configuration, yakni webpack.common.jswebpack.dev.jswebpack.prod.js.
2020031320460608a25f67deb0b9b3e814f9dd16627dd5.png
Kita tuliskan konfigurasi pada berkas webpack.common.js terlebih dahulu. Buka berkas tersebut dan tuliskan konfigurasi berikut:
  1. const HtmlWebpackPlugin = require("html-webpack-plugin");
  2. const path = require("path");
  3.  
  4. module.exports = {
  5.    entry: "./src/app.js",
  6.    output: {
  7.        path: path.resolve(__dirname, "dist"),
  8.        filename: "bundle.js"
  9.    },
  10.    module: {
  11.        rules: [
  12.            {
  13.                test: /\.css$/,
  14.                use: [
  15.                    {
  16.                        loader: "style-loader"
  17.                    },
  18.                    {
  19.                        loader: "css-loader"
  20.                    }
  21.                ]
  22.            }
  23.        ]
  24.    },
  25.    plugins: [
  26.        new HtmlWebpackPlugin({
  27.            template: "./src/index.html",
  28.            filename: "index.html"
  29.        })
  30.    ]
  31. }

Kemudian buka berkas webpack.dev.js dan tuliskan konfigurasi berikut pada berkas tersebut:
  1. const merge = require("webpack-merge");
  2. const common = require("./webpack.common");
  3.  
  4. module.exports = merge(common, {
  5. mode: "development"
  6. })

Lalu pada berkas webpack.prod.js tuliskan juga konfigurasi berikut:
  1. const merge = require("webpack-merge");
  2. const common = require("./webpack.common");
  3.  
  4. module.exports = merge(common, {
  5.    mode: "production",
  6.    module: {
  7.        rules: [
  8.            {
  9.                test: /\.js$/,
  10.                exclude: "/node_modules/",
  11.                use: [
  12.                    {
  13.                        loader: "babel-loader",
  14.                        options: {
  15.                            presets: ["@babel/preset-env"]
  16.                        }
  17.                    }
  18.                ]
  19.            }
  20.        ]
  21.    }
  22. })

Karena pada konfigurasi kita menentukan endpoint pada lokasi src -> app.js dan HTML template pada lokasi src -> index.html, maka pindahkan kedua tersebut ke dalam folder src.
202003132048035864b91c77743870eb2fbf052f0b9d0b.png
Selanjutnya buka berkas index.html lalu hapus kode:

  1. <link rel="stylesheet" href="src/styles/style.css">



Dan juga kode:

  1. <script src="app.js" type="module"></script>



Karena kita sudah tidak memerlukan impor CSS dan JS melalui berkas HTML. 
Sebagai gantinya kita perlu impor berkas CSS dan sesuaikan kembali lokasi impor dari app-bar.js dan main.js pada entry point yaitu app.js.

  1. import "./styles/style.css";

  2. import "./script/component/app-bar.js";

  3. import main from "./script/view/main.js";

  4.  

  5. document.addEventListener("DOMContentLoaded", main);



Terakhir kita ubah scripts yang berada pada package.json untuk menjalankan proyek Club Finder.
  1. {
  2.  "name": "clubfinder",
  3.  "version": "1.0.0",
  4.  "description": "",
  5.  "main": "app.js",
  6.  "scripts": {
  7.    "start-dev": "webpack-dev-server --config webpack.dev.js --open",
  8.    "build" : "webpack --config webpack.prod.js"
  9.  },
  10.  "author": "",
  11.  "license": "ISC",
  12.  "devDependencies": {
  13.    "@babel/core": "^7.8.7",
  14.    "@babel/preset-env": "^7.8.7",
  15.    "babel-loader": "^8.0.6",
  16.    "css-loader": "^3.4.2",
  17.    "html-loader": "^0.5.5",
  18.    "html-webpack-plugin": "^3.2.0",
  19.    "style-loader": "^1.1.3",
  20.    "webpack": "^4.42.0",
  21.    "webpack-cli": "^3.3.11",
  22.    "webpack-dev-server": "^3.10.3",
  23.    "webpack-merge": "^4.2.2"
  24.  }
  25. }

Voila! Sekarang kita bisa menjalankan proyek Club Finder melalui perintah

  1. npm run start-dev


Kita juga bisa melakukan build untuk production melalui perintah

  1. npm run build


Dengan begitu akan terbentuk berkas bundle.js dan index.html yang siap untuk di-deploy.
2020031320503945178a86d7a7b327f3e90b1f510fb823.png
Untuk memastikan proyek hasil build berjalan dengan baik, kita dapat membuka berkas index.html pada browser melalui lokal web server dengan menjalankan perintah:

  1. http-server ./dist


20200313205112d8d29c4b7f29e1a3ed4f39197078d603.png
Oh ya, jika pada kode Anda terdapat async/await dan menerapkan babel-loader pada webpack seperti instruksi yang sudah diajarkan, maka proyek Club Finder akan mengalami eror seperti ini ketika melakukan pencarian club:

  1. Uncaught ReferenceError: regeneratorRuntime is not defined


202003132052101e4d73d58d18a6212ad56779b23542d9.png
Untuk mengatasinya, kita perlu memasang package regenerator-runtime pada dependencies dengan menggunakan npm:

  1. npm install regenerator-runtime



Kemudian import package tersebut pada entry point.

  1. import "regenerator-runtime";

  2. import "./styles/style.css";

  3. import "./script/component/app-bar.js";

  4. import main from "./script/view/main.js";

  5.  

  6. document.addEventListener("DOMContentLoaded", main);



Dengan begitu seharusnya proyek hasil build akan bekerja sesuai dengan harapan.
20200313205328f8ea2fb4177b0b2d795d728a4eddc2ca.png

Langkah dari materi ini bisa Anda temukan juga pada repository berikut:
https://github.com/dicodingacademy/a163-bfwd-labs/tree/111-club-finder-webpack-solution