What is Webpack?
Pada hakikatnya webpack merupakan module bundler untuk aplikasi JavaScript modern. Saat webpack dijalankan pada proyek kita, di belakang layar webpack akan mengobservasi module apa saja yang kita pakai dan membuat modul-modul itu dibungkus jadi satu berkas (atau lebih).
Dengan memakai webpack kita bisa bebas memakai module yang saling bergantungan. Webpack akan menggabungkan semua module yang dipakai baik itu modul yang kita tuliskan sendiri atau module yang kita raih melalui NPM jadi static assets yang siap dipakai pada tahap produksi.
Webpack pertama kali dirilis pada tanggal 10 Maret 2012. Sebelum ada webpack sebetulnya telah terdapat tools lain yang serupa seperti Browserify. Disamping sebagai module bundler, browserify sejatinya mempunyai tujuan sebagai tools yang bisa membawa node package apapun supaya bisa berjalan pada browser (kita bisa melihat tujuan dari namanya “Browserify”).
Secara tidak langsung dia perlu berperan sebagai module bundler. Alasannya, saat memakai node package, tentu package itu terpisah dari kode yang kita tuliskan sendiri. Untuk menggabungkannya, Node.js memakai perintah require(). Dengan memakai browserify ini, perintah require() itu bisa kita pakai pada browser (melalui transpiling).
Dari sisi konsep, browserify dan webpack amatlah berbeda. Tetapi kita bisa mengkategorikan keduanya sebagai module bundler. Kelebihan webpack dibandingkan dengan browserify yaitu webpack bisa memproses berkas/module lain diluar JavaScript seperti TypeScript, Sass tanpa bantuan task runner seperti Grunt atau Gulp.
Sekitar awal tahun 2014 sampai pertengahan tahun 2015 browserify ini populer dipakai oleh developer. Sampai di akhir tahun 2015 webpack-lah yang menggantikan kepopulerannya. Sekarang ini webpack telah menyentuh versi 4 dengan mengusung kemampuan zero configuration-nya.
Core Concepts
Untuk lebih mengerti bagaimana webpack bekerja, ketahui dulu core concepts yang ada di webpack.
Terdapat 5 (lima) konsep penting dalam webpack yang harus kita ketahui sebelum memakai webpack itu sendiri. Dari 5 (lima) konsep itu kita tahu bagaimana perilaku dari webpack saat dia dijalankan. Berikut penjelasan singkat dari kelima konsep itu:
-
- 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 jadi format yang bisa dipakai ke tahap produksi.
-
- Plugin : Dipakai untuk melakukan tugas seperti optimasi bundel, management aset dan lain-lain.
-
- Mode : Keadaan yang dipakai webpack sebagai acuan optimasi apa saja yang perlu diterapkan dalam melakukan tugasnya. Dalam mode kita bisa menetapkan nilai production, development maupun none
Entry
Entry atau entry point merupakan modul pertama yang akan dianalisa oleh webpack saat dia dijalankan. Melalui entry point inilah webpack akan membentuk dependency graph. Webpack akan mencari tahu modul lain yang dipakai pada entry point dan menggabungkannya jadi satu static assets.
Pada webpack 4 standarnya nilai entry point akan ditempatkan pada ./src/index.js. Tetapi kita bisa menetapkan tempat yang beda dengan mengatur properti entry pada berkas webpack configuration (webpack.config.js). Misalnya:
-
- module.exports = {
-
- entry: ‘./path/to/my/entry/file.js’
- };
Kode di atas merupakan cara cepat dalam penulisan properti entry. Sebetulnya entry bisa berupa objek semacam ini:
-
- module.exports = {
-
- entry: {
-
- main: ‘./path/to/my/entry/file.js’
-
-
- }
- };
-
Kita dapat memanfaatkan objek sebagai nilai entry saat ada banyak entry point yang mau kita tetapkan.
-
- module.exports = {
-
- entry: {
-
- app: ‘./src/app.js’,
-
- adminApp: ‘./src/adminApp.js’
-
-
- }
- }
-
Output
Output adalah salah satu properti yang terdapat di webpack configuration. Properti ini berguna untuk memberitahu webpack di mana dan bagaimana tempat static assets yang sudah dibundel harus disimpan dan dinamai. Standarnya tempat penyimpanannya berada di dist -> main.js. Tempat dist merupakan tempat standar untuk menyimpan berkas yang dihasilkan oleh webpack.
Kita bisa mengkonfigurasi bagian output ini melalui properti output pada webpack.config.js seperti contoh berikut ini:
-
- const path = require(‘path’);
-
- module.exports = {
-
- entry: ‘./path/to/my/entry/file.js’,
-
- output: {
-
- path: path.resolve(__dirname, ‘dist’),
-
- filename: ‘my-first-webpack.bundle.js’
-
-
- }
- };
-
Dalam contoh di atas, kita memakai output.filename dan output.path properties untuk memberitahu webpack penamaan dan tempat static assets yang telah dibundel. Dalam contoh di atas juga kita bisa melihat modul path yang diimpor memakai Node.js module. Modul itu merupakan modul standar pada Node.js yang dipakai untuk memanipulasi tempat berkas.
Bila kita menetapkan lebih dari satu entry point, kita harus memakai substitution untuk memastikan berkas yang dihasilkan webpack mempunyai nama unik.
-
- module.exports = {
-
- entry: {
-
- app: ‘./src/app.js’,
-
- search: ‘./src/search.js’
-
- },
-
- output: {
-
- filename: ‘[name].js’,
-
- path: __dirname + ‘/dist’
- }
- };
-
// webpack akan menghasilkan: ./dist/app.js, ./dist/search.js
-
Properti output mempunyai banyak fitur pada proses konfigurasinya.
Loaders
Dalam melaksanakan tugas, sejatinya webpack cuma mengenali berkas JavaScript dan JSON. Tetapi melalui loaders webpack bisa memproses berkas berformat lain seperti css, sass, pug, jsx atau yang lainnya. Loaders merupakan suatu transformation tools pada webpack yang akan memproses setiap berkas selain JavaScript atau JSON yang kita impor jadi format yang bisa dipakai ke tahap produksi.
Bila pada build tools lain seperti Gulp atau Grunt, loaders ini seperti “task”. Task ini amat membantu dalam menangani proses front-end building. Loader bisa merubah berkas bahasa pemrograman lain seperti TypeScript ke JavaScript. Yang amat spesial dari loader ini kita bisa melakukan import berkas .css langsung di entry point pantasnya berkas JavaScript pada dependency graph.
Kemampuan impor pada modul apapun (misalnya .css) merupakan fitur rinci dari webpack yang boleh jadi tidak akan kita temui pada module bundler atau task runner lain. Akhirnya, kita bisa lebih bebas lagi alias tidak terbatas dengan tipe berkas dalam memakai module pada webpack.
Untuk menetapkan loaders kita pakai properti module.rules pada webpack configuration (webpack.config.js). Di dalamnya terdapat dua high level properties yaitu test, dan use. Berikut penjelasan ringkasnya:
- Properti test merupakan tipe berkas yang akan ditransformasikan.
- Properti use merupakan loader mana yang akan dipakai untuk mentransformasikan berkas itu.
Belum terpikirkan bagaimana penggunaannya? Berikut contoh konfigurasi dari properti loader:
-
- module.exports = {
-
- module: {
-
- rules: [
-
- { test: /.css$/, use: ‘css-loader’ }
-
- ]
-
-
- }
- };
-
Konfigurasi di atas mempunyai properti module.rules dan menetapkan properti test dan use di dalamnya. Konfigurasi semacam ini pantasnya kita memberitahu “Hey webpack compiler! Saat Kamu berjumpa dengan berkas .css yang dihubungkan memakai import atau require statement, pakailah css-loader untuk mengubahnya sebelum membungkusnya ke dalam bundle”.
Banyak sekali loader yang bisa kita pakai pada webpack configuration. Tetapi loader itu tidak dilampirkan langsung saat kita memakai webpack. Bila kita mau memakai loader katakanlah css-loader, maka kita harus memasang package loader itu melalui npm.
- npm install css–loader —save–dev
Contoh sebelumnya merupakan cara ringkas saat kita menetapkan loader supaya mudah dibaca. Melalui module.rules sebetulnya kita bisa menetapkan banyak loader, tetapi dalam penulisannya kita harus menetapkan loader itu secara eksplisit semacam ini:
-
- module.exports = {
-
- module: {
-
- rules: [
-
- {
-
- test: /.css$/,
-
- use: [
-
- {
-
- loader: “style-loader”
-
- },
-
- {
-
- loader: “css-loader”
-
- }
-
- ]
-
- }
-
- ]
-
-
- }
- }
-
Dalam menuliskan banyak loader dalam satu rule, urutan deklarasi loader itu sangat berefek. Loader akan tereksekusi dengan urutan dari bawah ke atas. Dalam contoh di atas eksekusi akan dimulai dari css-loader, lalu dilanjutkan oleh style-loader.
Dengan menuliskan loader secara eksplisit semacam ini, kita juga bisa dengan gampang menambahkan konfigurasi pada loader yang dipakai melalui properti options. Misalnya:
-
- module.exports = {
-
- module: {
-
- rules: [
-
- {
-
- test: /.css$/,
-
- use: [
-
- {
-
- loader: “style-loader”,
-
- options: {
-
- // memasukkan style dengan tag <style> di bawah dari element <body>
-
- insert: “body”
-
- }
-
- },
-
- {
-
- loader: “css-loader”
-
- }
-
- ]
-
- }
-
- ]
-
-
- }
- }
-
Untuk melihat loader apa saja yang bisa kita manfaatkan pada webpack dan konfigurasi apa saja yang bisa diimplementasikan pada masing-masing loadernya, kita bisa menatapnya secara lengkap pada dokumentasi resmi webpack.
Plugin
Plugin pada webpack dipakai untuk melakukan tugas seperti optimasi bundel, management aset dan lain-lain. Dengan adanya plugin ini, webpack jadi lebih fleksibel. Plugin merupakan tulang punggung dari webpack. Bahkan webpack sendiri dibangun menerapkan sistem plugin yang sama seperti yang kita lakukan pada webpack configuration.
Webpack Plugin merupakan suatu JavaScript objek yang dibangun memakai JavaScript class yang di dalamnya terdapat method apply dengan satu argument bernama compiler. Kita bisa membuat webpack plugin sederhana dengan metode semacam ini:
- ConsoleLogOnBuildWebpackPlugin.js
-
- const pluginName = ‘ConsoleLogOnBuildWebpackPlugin’;
-
- class ConsoleLogOnBuildWebpackPlugin {
-
- constructor(options) {
-
- this.options = options;
-
- }
-
- apply(compiler) {
-
- compiler.hooks.run.tap(pluginName, compilation => {
-
- console.log(this.options.message);
-
- });
-
- }
-
- }
-
- module.exports = ConsoleLogOnBuildWebpackPlugin;
-
Saat kita memakai plugin itu pada webpack configuration, dia akan mencetak nilai this.options.message pada console saat proses build pada webpack berjalan.
Untuk sekarang ini jangan terfokus pada cara membuat plugin di webpack. Bukannya, fokuslah pada bagaimana dia dipakai pada webpack configuration. Sebab plugin merupakan objek dan kita mungkin menyimpan konfigurasi saat dia dibuat, maka dalam membuat objek plugin kita harus memakai keyword new semacam ini:
-
- const ConsoleLogOnBuildWebpackPlugin = require(“./console-log-on-build-webpack-plugin.js”);
-
- module.exports = {
-
- plugins: [
-
- new ConsoleLogOnBuildWebpackPlugin({
-
- message: “The webpack build process is starting!”
-
- })
-
-
- ]
- }
-
Banyak plugin baik standar webpack atau pihak ke-3 yang bisa kita manfaatkan pada webpack. Sebab itulah kita tidak harus fokus terhadap bagaimana membuat plugin. Untuk memakai plugin standar webpack, kita bisa mengaksesnya melalui objek webpack semacam ini:
-
- const webpack = require(“webpack”); // diperlukan untuk mengakses built-in plugins
-
- module.exports = {
-
- plugins: [
-
- new webpack.ProgressPlugin()
-
-
- ]
- }
-
Tetapi, untuk memakai beberapa plugin (di luar plugin standar yang disiapkan) kita harus memasangnya terlebih dulu melalui npm. Misalnya plugin yang banyak dipakai untuk membuat berkas HTML pada webpack ialah html-webpack-plugin. Untuk memasangnya kita pakai perintah berikut:
- npm install html–webpack–plugin —save–dev
Sesudah memasangnya kita bisa memakainya pada webpack configuration semacam ini:
-
- const HtmlWebpackPlugin = require(‘html-webpack-plugin’); //dipasang via npm
-
- module.exports = {
-
- plugins: [
-
- new HtmlWebpackPlugin({
-
- template: “./src/index.html”,
-
- filename: “index.html”
-
- })
-
-
- ]
- };
-
Dalam contoh di atas, melalui html-webpack-plugin webpack akan menghasilkan berkas HTML untuk proyek kita dan memasukkan berkas yang telah dibundel.
Mode
mode adalah salah satu properti yang terdapat di webpack configuration. Dengan memberikan mode dengan nilai development, production atau none, kita bisa melakukan optimasi pada webpack berdasarkan mode yang kita kehendaki. Bila kita tidak menetapkan nilai pada properti mode, secara default akan bernilai production.
-
- module.exports = {
-
-
- mode: ‘production’
- };
-
Nilai mode juga bisa kita tetapkan melalui CLI argument seperti berikut:
- webpack —mode development
Kita bisa melakukan optimasi pada webpack berdasarkan mode yang kita kehendaki sebab tiap properti pada webpack configuration menyesuaikan pada modenya. Misalnya, bila kita memakai mode development, kita bisa memakai properti devtool, cache, atau properti development lainnya pada webpack configuration.
-
- module.export = {
-
- mode: ‘development’,
-
-
- devtool: ‘eval’,
- cache: ‘true’}
-
Properti devtool atau cache tentu tidak bisa kita pakai dalam mode production, namun kita bisa memanfaatkan properti-properti yang terdapat di production. Begitu juga saat kita menetapkan mode none.
Bila kita mau merubah perilaku webpack berdasarkan nilai mode di dalam webpack.config.js, kita fungsi bukannya objek.
-
- const config = {
-
- entry: ‘./app.js’
-
- //…
-
- };
-
- module.exports = (env, argv) => {
-
- if (argv.mode === ‘development’) {
-
- config.devtool = ‘source-map’;
-
- }
-
- if (argv.mode === ‘production’) {
-
- //…
-
- }
-
- return config;
- };
Atau kita bisa memakai flag –config pada scripts berkas package.json untuk menetapkan berkas webpack configuration yang berbeda pada tiap modenya.
-
- “scripts”: {
-
- “build:prod”: “webpack –config webpack.prod.js”,
-
-
- “build:dev”: “webpack –config webpack.dev.js”,\
- }
-
Using Webpack
Sesudah mengetahui apa itu webpack dan seperti apa core concepts-nya, mungkin sebagian dari kita masih bingung bila belum mencobanya langsung. Untuk itu ayo kita coba terapkan webpack pada proyek WebClock yang telah kita buat sebelumnya. Sebab pada proyek itu kita masih memakai tag <script> dalam memakai package yang terpasang memakai npm.
Sebelum melanjutkan ke materi berikutnya. Pastikanlah kamu ikuti arahan pada modul Node Package Manager sampai proyek WebClock menghadirkan tampilan semacam ini:
Belum ada tampilan demikian? Ayo baca kembali modul pada Node Package Manager dan ikuti arahan di sana. Untuk Kamu yang telah sampai tahap itu, mari kita pakai webpack mulai dari cara memasangnya.
Installing Webpack
Memasang webpack pada proyek kita sama seperti kita memasang package JQuery atau Moment.js. Tetapi webpack ini dipasang pada devDependencies sebab sejatinya dia cuma dipakai selama proses pengembangan saja.
Untuk memasang webpack silakan buka proyek Kamu. Pada terminal kita tuliskan perintah berikut:
-
-
- npm install webpack —save–dev
- npm install webpack–cli —save–dev
-
Atau kita bisa menyingkat perintah itu dalam penulisan satu baris semacam ini:
- npm install webpack webpack–cli —save–dev
Sesudah berhasil memasang package webpack dan webpack-cli, maka kita bisa melihat kedua package itu pada devDependencies di berkas package.json.
Kenapa kita memerlukan 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 dipakai untuk membantu kita menjalankan webpack melalui sebuah perintah (Command Line Interface). Pada CLI juga kita bisa memberikan argumen seperti menetapkan berkas webpack config, atau mode pada proses build.
Untuk menjalankan webpack kita harus menambahkan script dengan perintah webpack pada package.json semacam ini:
-
- “scripts”: {
-
- “test”: “echo “Error: no test specified” && exit 1″,
-
- “start”: “http-server .”,
-
-
- “build”: “webpack”
- },
-
Kita dapat menghapus script yang lainnya sebab sudah akan kita pakai lagi. Sehingga sekarang berkas package.json akan terlihat semacam ini:
-
- {
-
- “name”: “webclock”,
-
- “version”: “1.0.0”,
-
- “description”: “”,
-
- “main”: “index.js”,
-
- “scripts”: {
-
- “build”: “webpack”
-
- },
-
- “author”: “”,
-
- “license”: “ISC”,
-
- “dependencies”: {
-
- “jquery”: “^3.4.1”,
-
- “moment”: “^2.24.0”
-
- },
-
- “devDependencies”: {
-
- “webpack”: “^4.41.6”,
-
- “webpack-cli”: “^3.3.11”
-
-
- }
- }
-
Lalu untuk menjalankan script build, kita pakai perintah berikut:
- npm run build
Tetapi untuk sekarang ini bila menjalankan script build akan terjadi eror semacam ini:
Dari pesan berikut, kita bisa menyimpulkan bahwa saat kita tidak/belum menetapkan webpack configuration, nilai entry standarnya akan berlokasi pada src -> index.js.
- ERROR in Entry module not found: Error: Can‘t resolve ‘./src‘ in ‘C:UsersDicodingDesktopWebClock‘
Untuk itu ayo kita sesuaikan dengan membikin folder src dan memindahkan index.js pada folder itu. Sehingga struktur proyeknya akan terlihat semacam ini:
Lalu coba kita jalankan kembali script build, maka hasilnya akan terlihat semacam ini:
Pada struktur proyek kita juga tampak terdapat folder baru dengan nama dist, di mana di dalamnya terdapat berkas main.js yang merupakan hasil bundel dari entry point src -> index.js.
Bila kita buka berkas itu, akan tampil banyak kode yang susah kita baca. Tidak perlu khawatir terkait kode yang dihasilkan webpack itu. Tetapi bila dilihat di akhir kodenya, kita akan mendapatkan kode asli yang kita tulis.
Sebab kita telah memakai webpack untuk membundel module. Kita bisa memakai perintah import pada src -> index.js dalam memakai package npm.
-
- import $ from “jquery”;
-
- import moment from “moment”;
-
- const displayTime = () => {
-
- moment.locale(“id”);
-
- $(“.time”).text(moment().format(“LTS”));
-
- $(“.date”).text(moment().format(“LL”));
-
- };
-
- const updateTime = () => {
-
- displayTime();
-
- setTimeout(updateTime, 1000)
-
- };
-
- updateTime();
Lalu pada index.html, kita bisa menggantikan semua tag <script> yang ada dengan satu tag <script> yang ditujukan pada dist -> main.js.
-
- <!DOCTYPE html>
-
- <html>
-
- <head>
-
- <title>Clock Web</title>
-
- <link rel=“stylesheet” href=“style.css”>
-
- </head>
-
- <body>
-
- <div class=“clock”>
-
- <span class=“time”></span>
-
- <span class=“date”></span>
-
- </div>
-
- <script src=“./dist/main.js”></script>
-
-
- </body>
- </html>
-
Kemudian kita build ulang proyek dengan menjalankan perintah:
- npm run build
Sesudah build selesai dan menghasilkan berkas dist -> main.js yang baru, proyek WebClock semestinya telah dapat berjalan dengan bagus saat kita membuka berkas index.html.
Creating configuration files
Sebelumnya kita memakai webpack dengan zero configuration. Apa artinya? Kita bisa memakai webpack tanpa membuat berkas webpack configuration sama sekali. Zero configuration ini fitur baru dari webpack 4. Tetapi kekurangan dalam zero configuration ialah kita tidak bisa menyesuaikan konfigurasi yang kita harapkan saat memakai webpack. Katakanlah bila kita harus memakai sebuah loader atau plugin, tentu dengan zero configuration kita tidak bisa memakainya.
Kita bisa membuat berkas webpack configuration dengan membikin berkas JavaScript baru dengan nama webpack.config.js pada root folder proyek kita.
Nama berkas itu merupakan nama standar bagi berkas webpack configuration. Kita bisa menentukan nama lain sesuka kita tetapi kita harus menambahkan argument –config pada webpack CLI. Kita akan mencoba hal ini nanti. Sekarang ini kita fokus dulu bagaimana cara menuliskan sintaks pada berkas webpack configuration.
Pada materi sebelumnya kita telah mengenal konsep inti dari webpack ini. Ada entry, output, loader, plugins dan mode. Kelima konsep inti itu bisa menentukan perilaku webpack dalam melaksanakan tugasnya. Untuk konfigurasi awal, kita tetapkan terlebih dulu entry dan output pada webpack configuration. Caranya dengan tambahkan kode berikut pada berkas webpack.config.js.
-
- const path = require(“path”);
-
- module.exports = {
-
- entry: “./src/index.js”,
-
- output: {
-
- path: path.resolve(__dirname, “dist”),
-
- filename: “bundle.js”
-
-
- }
- }
-
Pada nilai entry meskipun kita menetapkannya tetapi tak ada nilai yang berbeda seperti nilai standar yaitu src -> index.js. Tetapi pada nilai output, kita merubah penamaan berkas hasil bundel dari main.js (nilai standar) jadi bundle.js. Sehingga saat kita jalankan kembali script build.
- npm run build
Maka akan terdapat berkas bundel baru bernama bundle.js.
Tetapi kita juga masih bisa melihat berkas main.js yang merupakan berkas lama hasil proses build sebelumnya. Kita bisa menghapusnya sebab sudah dipakai lagi. Tetapi jangan sampai lupa merubah target berkas JavaScript yang disertakan pada index.html jadi bundle.js.
-
- <!DOCTYPE html>
-
- <html>
-
- <head>
-
- <title>Clock Web</title>
-
- <link rel=“stylesheet” href=“style.css”>
-
- </head>
-
- <body>
-
- <div class=“clock”>
-
- <span class=“time”></span>
-
- <span class=“date”></span>
-
- </div>
-
- <script src=“./dist/bundle.js”></script>
-
-
- </body>
- </html>
-
Bila kita membuka index.html maka akan tampil hasil yang sama seperti sebelumnya. Sebab memang kita tidak melakukan apapun selain merubah nama hasil bundel dari main.js (nilai standar) jadi bundle.js.
Pada ketika proses bundle, coba kita lihat pada Terminal. Terdapat warning yang menjelaskan bahwa kita tidak menetapkan mode pada berkas webpack configuration.
Bila kita tidak menetapkan nilai pada properti mode maka nilai standar akan diterapkan, yaitu nilai production. Tetapi ketimbang kita membiarkan properti mode ini tidak mempunyai nilai, disarankan kita tetapkan saja nilai modenya. Untuk sekarang ini, kita tetapkan properti mode dengan nilai production.
-
- const path = require(“path”);
-
- module.exports = {
-
- entry: “./src/index.js”,
-
- output: {
-
- path: path.resolve(__dirname, “dist”),
-
- filename: “bundle.js”
-
- },
-
-
- mode: “production”
- }
-
Lalu coba jalankan kembali script build. Maka warning terkait properti mode tak akan muncul pada Terminal ketika proses build berjalan.
“Sebetulnya kita juga bisa melihat warning lain yang menunjukkan ukuran bundle.js telah melampaui batas. Kita dapat lihat sendiri dengan membuka berkas bundle.js. Di sana kita akan mendapatkan banyak sekali kode yang dihasilkan dibandingkan dengan sebelumnya.Hal ini dikarenakan kode yang kita tulis mempunyai ketergantungan (dependencies) terhadap package JQuery dan Moment. Sehingga package itu perlu dibundel pula pada berkas bundle.js. sebab itulah berkas bundle.js jadi bengkak ukurannya.Ini adalah salah satu alasan kenapa disarankan kita hindari pemakaian package pihak ke-3 yang kita bawa sampai tingkat production. Membengkaknya berkas bundle.js, pasti akan berakibat terhadap kinerja web yang kita bangun nantinya.”
Using Loader
Pada penjelasan core concepts kita telah tahu bahwa dengan loader, webpack bisa memproses berkas selain JavaScript. Dengan adanya loader kita bisa memakai CSS sebagai modul dan ikut terbundel bersama berkas bundle.js. Sehingga kita tidak harus lagi menerapkan tag <link> pada index.html.
Style and CSS Loader
Untuk memakai CSS modul pada webpack, kita memerlukan dua buah loader. Yang pertama css-loader dan yang kedua style-loader. css-loader merupakan loader untuk memproses berkas dengan format .css. Sedangkan style-loader merupakan loader yang dipakai untuk membuat styling bisa diterapkan secara modular dengan memakai import statement.
Untuk memakai kedua loader itu, tahap pertama ialah memasangnya melalui npm dengan perintah:
- npm install style–loader css–loader —save–dev
Sesudah berhasil, pada berkas webpack.config.js kita tambahkan properti module.rules dan isikan nilai loader semacam ini:
-
- const path = require(“path”);
-
- module.exports = {
-
- entry: “./src/index.js”,
-
- output: {
-
- path: path.resolve(__dirname, “dist”),
-
- filename: “bundle.js”
-
- },
-
- mode: “production”,
-
- module: {
-
- rules: [
-
- {
-
- test: /.css$/,
-
- use: [
-
- {
-
- loader: “style-loader”
-
- },
-
- {
-
- loader: “css-loader”
-
- }
-
- ]
-
- }
-
- ]
-
-
- }
- }
-
Sesudah menambahkan loader pada webpack.config.js, sekarang kita bisa melakukan impor berkas CSS memakai import statement pantasnya berkas JavaScript.
Tetapi sebelum itu, pindahkan terlebih dulu berkas style.css supaya lebih rapi ke dalam direktori baru dengan tempat src -> style -> style.css. Sehingga struktur proyek akan terlihat semacam ini:
Kemudian pada berkas index.js, lakukan impor berkas style.css di awal baris kodenya.
- import “./style/style.css”;
Maka keseluruhan kode pada index.js akan terlihat semacam ini:
import “./style/style.css”;
import nbsp;from “jquery”;
-
-
- import moment from “moment”;
- const displayTime = () => {
- moment.locale(“id”);
-
-
- $(“.time”).text(moment().format(“LTS”));
-
- $(“.date”).text(moment().format(“LL”));
-
-
- };
-
-
-
-
- const updateTime = () => {
- displayTime()
- const updateTime = () =>
setTimeout(updateTime, 1000)
-
-
-
-
- };
- updateTime();
-
Dengan seperti itu kita tidak memerlukan lagi tag <link> pada index.html dalam melampirkan stylesheet pada berkas style.css. Kita hapus tag <link> berikut:
- <link rel=“stylesheet” href=“style.css”>
Sehingga keseluruhan kode pada index.html akan terlihat semacam ini:
-
- <!DOCTYPE html>
-
- <html>
-
- <head>
-
- <title>Clock Web</title>
-
- </head>
-
- <body>
-
- <div class=“clock”>
-
- <span class=“time”></span>
-
- <span class=“date”></span>
-
- </div>
-
- <script src=“./dist/bundle.js”></script>
-
-
- </body>
- </html>
-
Sesudah itu coba jalankan kembali script build untuk menghasilkan berkas bundle.js yang baru dan buka index.html pada browser. Semestinya proyek WebClock menampilkan hasil yang sama seperti sebelumnya.
Selamat! Itu berarti, Kamu berhasil menerapkan styling dengan metode modular memakai webpack loader. Bila Kamu lihat pada berkas bundle.js sekarang ini, kita bisa mendapatkan styling yang dituliskan.
Hal inilah kenapa styling bisa diterapkan tanpa perlu memakai tag <link> pada berkas index.html.
Babel Loader
Kita telah berhasil memakai dan merasakan manfaat dari style-loader dan css-loader. Tetapi sebetulnya masih banyak loader lain yang tidak kalah pentingnya untuk diimplementasikan pada webpack. Salah satunya ialah babel-loader.
Mungkin sebagian dari kita telah ada yang mengetahui apa itu babel atau babel.js? Babel merupakan suatu transpiler yang bertugas untuk merubah sintaks JavaScript modern (ES6+) jadi sintaks yang bisa didukung penuh oleh semua browser.
JavaScript merupakan bahasa pemrograman yang berkembang sangat cepat. Komunitasnya besar, dan tiap tahun selalu terdapat versi yang baru. Tetapi perkembangan yang cepat tadi ternyata memerlukan waktu yang lama untuk diadaptasi oleh browser atau Node.js. Lalu bila kita mau mencoba sintaks paling baru di JavaScript apakah kita harus menanti sampai seluruh browser berhasil mengadaptasi pembaharuan itu? Tentu tidak!
Dengan babel Kamu bisa menuliskan sintaks JavaScript versi paling baru tanpa cemas memikirkan dukungan pada browser. Sebab babel akan merubah sintaks yang kita tuliskan jadi kode yang bisa diterima browser.
Bila Kamu penasaran bagaimana cara babel bekerja, babel menyediakan sebuah playground yang bisa kita manfaatkan untuk merubah sintaks JavaScript modern (ES6+) jadi sintaks lama.
Pada playground itu kita juga bisa memilih preset yang kita harapkan. Secara default preset akan mengarah ES2015 (ES6).
Kamu telah tahu sepintas terkait babel. Nah pada webpack kita juga bisa memakai babel dalam wujud loader. Meskipun webpack secara standarnya bisa memproses berkas JavaScript tanpa harus bantuan loader, tetapi proses itu tidak merubah sintaks yang kita tuliskan. Artinya bila kita menuliskan sintaks JavaScript modern, maka kita akan menemukannya pula pada berkas bundle.js.
Meskipun sekarang ini Google Chrome dan Mozilla Firefox telah mendukung penulisan sintaks ES6, tetapi setidaknya kita harus sedikit peduli terhadap dukungan browser lama seperti Internet Explorer atau browser versi lama lainnya.
Untuk memakai babel pada webpack sebagai loader, kita harus memasang tiga package memakai npm pada devDependencies. Yang pertama package @babel/core, yang kedua babel-loader, dan yang ketiga @babel/preset-env.
- npm install @babel/core babel–loader @babel/preset–env —save–dev
Package @babel/core merupakan package inti yang perlu dipasang saat kita ingin memakai babel, baik pada webpack ataupun tools yang lain.
Package babel-loader merupakan package yang dibutuhkan untuk memakai babel sebagai loader pada webpack.
Yang terakhir package @babel/preset-env merupakan package preset yang akan kita pakai untuk membantu babel-loader dalam melakukan tugasnya. @babel/preset-env merupakan preset cerdas yang memungkinkan kita memakai sintaks JavaScript paling baru tanpa menetapkan secara rinci sintaks JavaScript versi apa yang kita pakai.
Berkas package.json akan terlihat semacam ini sesudah memasang ketiga package itu:
-
- {
-
- “name”: “webclock”,
-
- “version”: “1.0.0”,
-
- “description”: “”,
-
- “main”: “index.js”,
-
- “scripts”: {
-
- “build”: “webpack”
-
- },
-
- “author”: “”,
-
- “license”: “ISC”,
-
- “dependencies”: {
-
- “jquery”: “^3.4.1”,
-
- “moment”: “^2.24.0”
-
- },
-
- “devDependencies”: {
-
- “@babel/core”: “^7.8.4”,
-
- “@babel/preset-env”: “^7.8.4”,
-
- “babel-loader”: “^8.0.6”,
-
- “css-loader”: “^3.4.2”,
-
- “style-loader”: “^1.1.3”,
-
- “webpack”: “^4.41.6”,
-
- “webpack-cli”: “^3.3.11”
-
-
- }
- }
-
Sesudah berhasil memasang ketiga package itu, langkah berikutnya kita bisa pakai babel-loader dan preset-nya pada webpack configuration.
-
- const path = require(“path”);
-
- module.exports = {
-
- entry: “./src/index.js”,
-
- output: {
-
- path: path.resolve(__dirname, “dist”),
-
- filename: “bundle.js”
-
- },
-
- mode: “production”,
-
- module: {
-
- rules: [
-
- /* style and css loader */
-
- {
-
- test: /.css$/,
-
- use: [
-
- {
-
- loader: “style-loader”
-
- },
-
- {
-
- loader: “css-loader”
-
- }
-
- ]
-
- },
-
- /* babel loader */
-
- {
-
- test: /.js$/,
-
- exclude: “/node_modules/”,
-
- use: [
-
- {
-
- loader: “babel-loader”,
-
- options: {
-
- presets: [“@babel/preset-env”]
-
- }
-
- }
-
- ]
-
- }
-
- ]
-
-
- }
- }
-
Saat menerapkan rule untuk berkas .js, jangan sampai lupa untuk menetapkan properti exclude dengan nilai “/node_modules/”. Apa artinya? Dengan memutuskan properti exclude itu artinya kita mengecualikan webpack untuk memproses berkas .js yang berada di folder “node_modules”. Hal ini bisa mengurangi proses yang tidak dibutuhkan, sehingga mempercepat proses build pada proyek kita.
Kemudian pada penerapan babel-loader juga kita memakai properti options dengan memutuskan properti presets di dalamnya. Pada properti presets kita tetapkan preset (dalam wujud array literas) yang telah kita pasang memakai npm, yaitu @babel/preset-env.
Sesudah memakai babel loader pada webpack configuration, ayo kita coba build dan buka kembali berkas bundle.js. Maka kode yang kita tuliskan dalam ES6 akan diubah dalam sintaks yang bisa diterima oleh semua browser.
Bahkan pada berkas bundle itu dipastikan sudah terdapat lagi sintaks yang dituliskan memakai ES6.
Tetapi meskipun sintaksnya telah diubah, proyek akan tetap berjalan normal seperti pada umumnya.
Webpack Dev Server
Sekarang ini setiap terjadi perubahan kode pada proyek, kamu harus melakukan build ulang untuk melihat hasilnya. Tidak peduli perubahan itu bersifat mayor maupun cuma sekadar ganti warna saja. Sebab untuk melihat perubahan paling baru kita juga harus memperbaharui berkas bundle.js. Tentu sangat menyusahkan bukan?
Untunglah webpack menyediakan fitur live-reloading yang bisa mempercepat proses pengembangan memakai Webpack Dev Server. Dengan ini kita bisa melihat perubahan secara langsung tanpa perlu menjalankan ulang perintah build.
Untuk memakai Webpack Dev Server tahap pertama ialah kita pasang package webpack-dev-server pada devDependencies memakai npm.
- npm install webpack–dev–server —save–dev
Sesudah berhasil memasangnya, kita tambahkan script start-dev dengan perintah “webpack-dev-server” pada package.json.
-
- “scripts”: {
-
- “build”: “webpack”,
-
-
- “start-dev”: “webpack-dev-server”
- }
-
Ayo kita jalankan script start-dev dengan perintah:
- npm run start–dev
Sesudah menjalankan perintah di atas, pada terminal kita bisa melihat alamat localhost:8080. Alamat itu dipakai untuk melihat proyek yang sedang kita kembangkan pada browser.
Webpack Dev Server secara standar mempunyai fitur live-reloading. Artinya setiap terjadi perubahan terhadap assets yang dipakai (HTML, CSS, atau JS) dan menyimpan perubahannya (save), dia akan melakukan melakukan proses compiling ulang dan menampilkan hasil perubahan langsung di browser.
Tetapi bila kita lihat proses compiling menghabiskan waktu yang cukup lama bukan? Dalam contoh gif di atas, butuh setidaknya 5 detik untuk Webpack Dev Server menampilkan perubahan paling baru pada browser. Kenapa bisa demikian?
Hal itu terjadi sebab kita memakai mode production dalam menggerakkan Webpack Dev Server. Saat memakai mode production maka webpack melakukan bundling module seoptimal mungkin sehingga proses memerlukan waktu lebih lama dibandingkan dengan mode development. Disamping itu, pada webpack configuration kita memakai babel-loader. Proses compiling yang lama akan terasa lebih lama lagi sebab kita perlu melewati proses transpiling kode JavaScript melalui babel-loader.
Solusinya, pisahkan webpack configuration untuk development dan production.
Untuk menghentikan service webpack-dev-server, pakai perpaduan ctrl + c pada terminal yang dipakai. Ingatlahbahwa disarankan kita hentikan service webpack-dev-server tiap kali mau melakukan perubahan pada berkas webpack configuration.
Configuration Environment
Tujuan dari development dan production memanglah berbeda. Pada tahap development webpack akan menerapkan konfigurasi yang sering maksimal agar mempercepat proses perubahan pada browser (hot reloading). Sedangkan dalam proses production kita mau fokus pada optimasi bundling dan kompatibilitasnya pada browser. Sebab perbedaan fokus itu disarankan kita memisahkan konfigurasi antara keduanya.
Tetapi bila berpedoman pada bagan di atas, antara keduanya terdapat konfigurasi umum (common) seperti entry, output, style-loader, css-loader dan HtmlWebpackPlugin. Untuk menghindari penulisan berulang, kita bisa memakai tools yang bernama webpack-merge yang berguna untuk menggabungkan konfigurasi umum dengan konfigurasi unik tiap environment-nya.
Using webpack-merge
Untuk memakai webpack-merge tahap pertama yaitu dengan memasang package itu pada devDependencies memakai NPM.
- npm install webpack–merge —save–dev
Lalu kita buat berkas webpack konfigurasi baru dengan nama webpack.common.js.
Di dalam berkas itu kita tuliskan konfigurasi umum yang dipakai pada setiap environment baik itu production atau development.
-
- const path = require(“path”);
-
- const HtmlWebpackPlugin = require(“html-webpack-plugin”);
-
- module.exports = {
-
- entry: “./src/index.js”,
-
- output: {
-
- path: path.resolve(__dirname, “dist”),
-
- filename: “bundle.js”
-
- },
-
- module: {
-
- rules: [
-
- /* style and css loader */
-
- {
-
- test: /.css$/,
-
- use: [
-
- {
-
- loader: “style-loader”
-
- },
-
- {
-
- loader: “css-loader”
-
- }
-
- ]
-
- }
-
- ]
-
- },
-
- /* plugin */
-
- plugins: [
-
- /* HTML Webpack Plugin */
-
- new HtmlWebpackPlugin({
-
- template: “./src/template.html”,
-
- filename: “index.html”
-
- })
-
-
- ]
- }
-
Lalu kita buat 2 (dua) berkas webpack configuration baru dengan nama webpack.prod.js dan webpack.dev.js.
Lalu pada masing-masing berkasnya, tuliskan kode berikut:
-
- webpack.prod.js
-
- const merge = require(“webpack-merge”);
-
- const common = require(“./webpack.common.js”);
-
- module.exports = merge(common, {
-
- mode: “production”,
-
- module: {
-
- rules: [
-
- /* babel loader */
-
- {
-
- test: /.js$/,
-
- exclude: “/node_modules/”,
-
- use: [
-
- {
-
- loader: “babel-loader”,
-
- options: {
-
- presets: [“@babel/preset-env”]
-
- }
-
- }
-
- ]
-
- }
-
- ]
-
-
- }
- })
-
- webpack.dev.js
-
- const merge = require(“webpack-merge”);
-
- const common = require(“./webpack.common.js”);
-
- module.exports = merge(common, {
-
-
- mode: “development”,
- })
-
Di dalam berkas webpack.common.js kita telah menetapkan nilai entry, output beberapa loader, dan plugin yang nilainya dipakai pada kedua environment. Sehingga kita tidak harus menetapkannya lagi pada masing-masing berkas konfigurasi environment-nya.
Teliti juga bahwa kita memakai merge() dari package webpack-merge, untuk memasukkan konfigurasi umum pada konfigurasi tiap environment-nya.
- module.exports = merge(common, … )
Sesudah menetapkan konfigurasi umum dan konfigurasi pada tiap environment, mari ubah perintah script build dan start-dev pada package.json jadi semacam ini:
-
- “scripts”: {
-
- “build”: “webpack –config webpack.prod.js”,
-
-
- “start-dev”: “webpack-dev-server –config webpack.dev.js”
- }
-
Dengan menambahkan flag –config [config-files] pada script build dan start-dev, maka Kamu bisa secara bebas menghapus berkas webpack.config.js sebab memang sudah dipakai lagi. Sehingga pada proyek WebClock cuma terdapat 3 (tiga) berkas webpack configuration.
Coba kita jalankan kembali script start-dev ya. Semestinya fitur live-reloading akan berlangsung lebih cepat.