Tutorial Konfigurasi Webpack — Vue JS

Reza Z. Ramadan
14 min readJan 29, 2020

Disclaimer

Pada tulisan ini, penulis tidak fokus dengan isi HTML, CSS dan JavaScript. Tulisan ini full membahas webpack dan cara konfigurasinya.

Berikut adalah hasil akhir dari projek ini https://github.com/RezaZR/tutorial-webpack

Apa Itu Webpack?

Webpack adalah sebuah module bundler untuk aplikasi JavaScript. Gunanya adalah untuk menggabungkan setiap aset, file, gambar, javascript, css, dependency, dll yang terdapat di dalam suatu projek menjadi grup file yang lebih kecil (bundle). Selain itu, webpack juga mengelola semua dependency yang terdapat pada projek kita, jadi kita tidak perlu lagi pusing-pusing dependency mana yang harus di-load pertama kali, karena webpack telah menyusunnya.

Untuk lebih mengerti apa itu Webpack, mari kita praktekkan secara langsung.

Inisialisasi

Sebelum melanjutkan, pastikan komputer kita telah terinstall node.js terlebih dahulu. Setelah itu buka command line dan ganti ke direktori yang diinginkan, lalu masukkan perintah

npm init

ke dalam command line. Perintah tersebut akan menghasilkan package.json yang berisi details yang telah kita isi pada saat melakukan perintah di atas.

Struktur Projek

Setelah melakukan inisialisasi, kita lanjutkan dengan membuat struktur projek yang akan kita gunakan nanti. Buatlah struktur projek seperti di bawah ini:

Berikut merupakan kegunaan dari tiap-tiap file yang pada gambar di atas:

webpack.config.js: Sudah dijelaskan di atas.

.babelrc.js: Babel merupakan compiler yang akan mengubah ECMAScript 2015+ menjadi sebuah kode yang cocok untuk versi javascript yang terdapat pada suatu browser.

package.json: File ini berisi metadata yang relevan terhadap projek. File ini memberikan informasi kepada npm untuk mengindentifikasi projek dan menangani semua dependensi yang terlibat di dalamnya.

folder /src: Folder ini akan berisi HTML, CSS dan JavaScript. Folder src atau source di sini berguna untuk memisahkan kode dari root files.

main.js: File ini nantinya akan menjadi entry point dari projek yang kita bangun menggunakan webpack. Dari file ini, webpack akan menelusuri semua file yang dibutuhkan lalu mengubahnya ke dalam suatu bundle.

index.html: Merupakan file html utama yang akan mengarahkan ke root vue yang ditunjuk.

App.vue: File ini merupakan root file dari vue yang telah didefiniskan pada main.js.

Install Dependencies

Mari kita install dependency yang akan kita gunakan. Tulis pada command line

npm i vue vue-loader vue-template-compiler webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env vue-style-loader css-loader html-webpack-plugin -D

Setelah melakukan command di atas, seperti ini kira-kira isi dari package.json:

{
"name": "tutorial-webpack",
"version": "1.0.0",
"private": true,
"description": "Tutorial menggunakan webpack",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Reza Zacky Ramadan",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.8.3",
"@babel/preset-env": "^7.8.3",
"babel-loader": "^8.0.6",
"css-loader": "^3.4.2",
"html-webpack-plugin": "^3.2.0",
"vue": "^2.6.11",
"vue-loader": "^15.8.3",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1"
}
}

Command -D akan memberi tahu npm bahwa kita akan menginstall dependency tersebut pada mode development.

Berikut merupakan penjelasan dari masing-masing dependecy yang kita gunakan:

vue: Sebuah framework javascript.

vue-loader & vue-template-compiler: Berguna untuk mengubah file .vue menjadi javascript.

webpack: Sudah dijelaskan di atas.

webpack-cli: Digunakan untuk menjalankan webpack command.

webpack-dev-server: Digunakan sebagai development server.

babel-loader, @babel/core & @babel/preset-env: Sudah dijelaskan pada Struktur Projek.

vue-style-loader: Mengambil css yang didapat dari css-loader dan menyuntikkannya ke dalam file html.

css-loader: Memuat semua css yang terdapat di dalam file .vue maupun file yang ada di dalam projek, mengubahnya ke dalam javascript lalu mengirimkannya kepada vue-style-loader.

html-webpack-plugin: Memuat index html yang ditunjuk sebagai entry point yang nantinya akan disuntik javascript yang telah dibundle.

Inisialisasi File

Masukkan kode-kode berikut ke dalam file:

App.vue:

<template>
<div id="app">
{{ message }}
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello World',
};
},
};
</script>
<style lang="scss">
#app {
font-size: 18px;
color: black;
}
</style>

index.html:

<html>
<head>
<title>Tutorial Webpack - Vue</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

main.js:

import Vue from 'vue';
import App from './App.vue';
new Vue({
render: h => h(App),
}).$mount("#app");

babelrc.js:

module.exports = {
presets: ['@babel/preset-env'],
}

Setelah memasukkan kode-kode dasar di atas, saatnya kita mengkonfigurasikan file webpack yang telah dibuat sebelumnya

webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = {
entry: './src/main.js',
module: {
rules: [
{ test: /\.js$/, use: 'babel-loader' },
{ test: /\.vue$/, use: 'vue-loader' },
{ test: /\.css$/, use: ['vue-style-loader', 'css-loader']},
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
new VueLoaderPlugin(),
]
};

Line 1 & 2: Kita harus mengimport 2 plugin yang kita akan gunakan terlebih dahulu. Normalnya, hanya plugin saja yang diimport, sedangkan loader dapat kita langsung pakai.

Line 5: Kita harus memberitahu webpack di mana entry point tempat ia akan bekerja. Pada kasus ini, kita memilih main.js sebagai entry point kita. Dari situ, webpack akan mulai menyisir kode kita.

Line 6–12: Pada module, kita akan memasukkan loader-loader yang kita butuhkan. Loader berguna untuk melakukan preprocessing terhadap file-file agar dapat dibundle. Untuk sekarang, kita menggunakan 4 loader, yaitu babel-loader, vue-loader, vue-style-loader dan css-loader. Untuk list loader lebih lengkap dapat dilihat di sini.

Line 13–18: Pada plugins, kita akan menggunakan 2 plugin yang telah diimport sebelumnya, yaitu HTMLWebpackPlugin yang langsung kita arahkan ke html utama dan VueLoaderPlugin. Untuk list plugin lebih lengkap dapat dilihat di sini.

Konfigurasi package.json

Setelah melewati langkah di atas, sekarang kita akan konfigurasi file package.json agar dapat menjalankan webpack. Ubahlah “test” menjadi “serve” yang terdapat dalam “scripts”. Kira-kira seperti ini isi dari package.json sekarang:

{
...,
"scripts": {
"serve": "webpack-dev-server --mode development"
},
...
}

Kita dapat memasukkan kata apa saja selain “serve”. Karena kita telah menamainya dengan “serve”, maka kita hanya perlu menulis

npm run serve

pada command line.

Jika berhasil, akan keluar bacaan Compiled succesfully. Setelah itu, kita dapat mengetahui di port mana projek tersebut berjalan. Bukalah localhost:8080 seperti yang terlihat pada gambar di atas untuk melihat hasilnya.

Jika Anda memasukkan kata selain “serve” berarti Anda harus memasukkan

npm run ***

dengan *** adalah kata yang Anda pilih.

Pada perintah “serve”, kita memberitahukan npm untuk menjalankan webpack-dev-server dengan mode development. Selain mode development, terdapat juga mode production. Dengan begitu kita dapat membedakan mana perintah untuk development, mana perintah untuk production, karena untuk mode production webpack akan mengecilkan ukuran dari kode yang terdapat dalam projek kita sesuai dengan konfigurasi yang kita masukkan.

Memisahkan Kode Internal dengan Kode Eksternal

Pada awalnya, kita hanya memberlakukan 1 entry point saja pada webpack.config.js. Sekarang kita harus memisahkan kode internal dengan kode eksternal, caranya adalah dengan menambahkan entry point menjadi 2 (pada kasus ini). Langsung saja tambahkan potongan kode ini pada webpack.config.js

...module.exports = {
entry: {
main: "./src/main.js",
vendor: "./src/vendor.js"
},
...
};

Sekarang tambahkan file vendor.js ke dalam folder src dan biarkan kosong untuk sekarang

Untuk mengujinya, kita harus menginstall kode eksternal. Mari kita uji dengan menginstall bootstrap

npm i bootstrap jquery popper.js

Pada contoh di atas, penulis juga memasukkan jquery dan popper.js karena keduanya dibutuhkan oleh bootstrap.

Setelah itu, masukkan kode ini ke dalam App.vue

<div id="app">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Navbar</a>
<button
class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div
class="collapse navbar-collapse"
id="navbarSupportedContent"
>
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#"
>Home <span class="sr-only">(current)</span></a
>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a
class
="nav-link dropdown-toggle"
href="#"
id="navbarDropdown"
role="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
Dropdown
</a>
<div
class="dropdown-menu" aria-labelledby="navbarDropdown"
>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#">Disabled</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input
class="form-control mr-sm-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
<button
class="btn btn-outline-success my-2 my-sm-0"
type="submit"
>
Search
</button>
</form>
</div>
</nav>
</div>

Kode tersebut merupakan kode navbar dari bootstrap.

Lalu import style bootstrap pada _main.scss:

@import "~bootstrap/scss/bootstrap";...

lalu jalankanlah command “serve” dan lihat hasilnya

Seperti yang dapat kita lihat, bootstrap telah berhasil diimport ke dalam projek kita.

Coba kecilkan layar browser Anda

maka header tersebut akan menjadi dropdown menu yang dapat dibuka lewat hamburger menu di kanan atas. Tapi apakah dapat dibuka? Tidak, karena navbar ini membutuhkan javascript untuk dapat berjalan.

Sekarang mari kita daftarkan bootstrap ke dalam vendor.js

require("bootstrap");

lalu restartlah server dan coba kembali. Pastinya sekarang navbar sudah dapat dibuka.

Sekarang, kode internal dan eksternal kita telah terpisah.

SASS Loader

Pada tahap ini, kita akan menambahkan sass loader ke dalam projek. Sass loader membutuhkan node-sass untuk dapat berjalan. Masukkan ke dalam command line

npm i node-sass sass-loader -D

Command tersebut akan menginstall node-sass dan sass-loader ke dalam package.json agar nanti dapat digunakan pada konfigurasi webpack.

Bukalah webpack.config.js lalu tambahkan rules berikut di bawah css:

const VueLoaderPlugin = require("vue-loader/lib/plugin");module.exports = {
...,
module: {
rules: [
...,
{
test: /\.s[ac]ss$/,
use: [
"vue-style-loader",
"css-loader",
{
loader: "sass-loader",
options: {
prependData: `
@import "./src/assets/styles/_main.scss";
`
}
}
]
}
]
}
};

Maksud dari potongan kode di atas adalah kita memberitahu sass-loader bahwa entry point dari file scss adalah _main.scss.

lalu tambahkanlah folder-folder dan file sehingga strukturnya menjadi seperti ini:

Isilah file _main.scss yang ada di dalam folder styles dengan styling sederhana. Abaikan dulu folder fonts dan images.

body {
background: antiquewhite;
}

lalu jalankan perintah “serve”. Seharusnya tampilan web telah terubah menjadi seperti ini

File Loader

Kali ini kita akan menambahkan file loader yang berguna untuk memuat file-file seperti gambar dan font. Langsung saja kita install

npm i file-loader -D

dan tambahkan loader tersebut pada module webpack.config.js

rules: [
...,
{
test: /\.(svg|jpg|jpeg|png|gif)(\?.*$|$)/,
use: {
loader: "file-loader",
options: {
name: "[name].[hash].[ext]",
outputPath: "images",
esModule: false
}
}
},
{
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: "file-loader",
options: {
name: "[name].[hash].[ext]",
outputPath: "fonts",
esModule: false
}
}
}
]

Tujuan memisahkan file-loader menjadi 2 adalah untuk mengetahui jika yang terbaca adalah gambar maka akan dibuatkan folder images dan jika yang terbaca adalah font maka akan dibuatkan folder fonts.

Setelah itu, coba masukkan gambar dan font pada assets/images dan assets/fonts. Lalu kita coba panggil gambar tersebut lewat App.vue

<template>
<div id="app">
...
<img src="./assets/images/images.png" alt="sample image" />
</div>
</template>

lalu panggil font tersebut lewat _main.scss

...
@font-face {
font-family: Rubik;
src: url("/src/assets/fonts/Rubik-Regular.ttf") format("truetype");
}
body {
...;
font-family: Rubik;
}

lalu daftarkan pada vendor.js

...require("./assets/fonts/Rubik-Regular.ttf");

setelah itu jalankan dengan memanggil command “serve”. Maka akan terlihat hasil seperti ini

Dengan menggunakan bantuan dari plugin chrome bernama WhatFont, kita dapat mengetahui bahwa font telah berubah sesuai dengan font pilihan kita. Gambarpun nampak terlihat di bawah navbar.

Menambahkan Command Build

Di sini kita akan menambahkan command “build” untuk menguji apakah loader kita telah berhasil mem-bundle file-file di atas. Tambahkan command ini pada package.json

{
...,
"scripts": {
...,
"build": "webpack --mode production"
},
...
}

Dapat dilihat, command “build” menggunakan mode production, berbeda dengan command “serve” yang menggunakan mode development.

Setelah itu tambahkan potongan kode ini ke dalam webpack.config.js

...const path = require("path");module.exports = {
...,
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist")
}
}

Maksud dari potongan kode tersebut adalah “Tolong keluarkan output bundle javascript dengan nama main.js dengan lokasi output file di dalam folder dist dan path sesuai dengan projek saya sekarang”.

Setelah itu, jalankan perintah

npm run build

pada command line dan tunggulah sampai command tersebut selesai dijalankan. Setelah selesai, pada projek akan keluar folder dist yang berisi main.js, main.css vendor.js dan index.html yang telah kita tunjuk menjadi entry point pada bagian Inisialisasi File di atas. Pada main.js carilah keyword “background:antiquewhite”

Jika ada, maka sass-loader telah berhasil kita konfigurasikan ke dalam webpack.

Memisahkan Mode Development dan Production

Tujuan memisahkan mode development dan production adalah agar pada mode production ukuran file tidak sebesar mode development.

Berikut merupakan contoh perbedaan ukuran file antara mode development dan production:

Mode Development
Mode Production

Dapat kita lihat bahwa main.js pada mode development memiliki ukuran 938 KiB, sedangkan main.js pada mode production hanya memiliki ukuran 131 KiB.

Pada contoh di atas juga terlihat bahwa pada mode production penulis memakai content hash untuk keperluan caching.

Cukup penjelasannya, mari kita langsung melakukan command install saja dengan menuliskan

npm i webpack-merge -D

setelah itu pecahlah webpack menjadi 3 seperti contoh pada gambar di bawah:

Note: webpack.config.js berubah menjadi webpack.common.js

lalu masukkanlah kode ini ke dalam:

webpack.common.js:

const VueLoaderPlugin = require("vue-loader/lib/plugin");module.exports = {
entry: {
main: "./src/main.js",
vendor: "./src/vendor.js"
},
plugins: [new VueLoaderPlugin()],
module: {
rules: [
{ test: /\.js$/, use: "babel-loader" },
{ test: /\.vue$/, use: "vue-loader" },
{
test: /\.(svg|jpg|jpeg|png|gif)(\?.*$|$)/,
use: {
loader: "file-loader",
options: {
name: "[name].[hash].[ext]",
outputPath: "images",
esModule: false
}
}
},
{
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: "file-loader",
options: {
name: "[name].[hash].[ext]",
outputPath: "fonts",
esModule: false
}
}
}
]
}
};

Pada webpack.common.js akan terdapat konfigurasi webpack yang dapat digunakan pada mode development dan production (general).

webpack.dev.js:

const HtmlWebpackPlugin = require("html-webpack-plugin");const path = require("path");
const common = require("./webpack.common");
const merge = require("webpack-merge");
module.exports = merge(common, {
mode: "development",
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist")
},
devServer: {
transportMode: "ws"
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html"
})
],
module: {
rules: [
{
test: /\.css$/,
use: ["vue-style-loader", "css-loader"]
},
{
test: /\.s[ac]ss$/,
use: [
"vue-style-loader",
"css-loader",
{
loader: "sass-loader",
options: {
prependData: `
@import "./src/assets/styles/_main.scss";
`
}
}
]
}
]
}
});

Pada webpack.dev.js terdapat konfigurasi webpack yang hanya diperuntukan pada mode development. Di sini kita mengimport module webpack.common.js untuk nantinya di-merge dengan konfigurasi webpack development dan production. Di sini, kita tidak melakukan minification, content hash atau optimization sama sekali, karena hanya untuk development saja.

webpack.prod.js:

const HtmlWebpackPlugin = require("html-webpack-plugin");const path = require("path");
const common = require("./webpack.common");
const merge = require("webpack-merge");
module.exports = merge(common, {
mode: "production",
output: {
filename: "[name].[hash].bundle.js",
path: path.resolve(__dirname, "dist")
},
optimization: {
minimizer: [
new HtmlWebpackPlugin({
template: "./src/index.html",
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true,
removeComments: true
}
})
]
},
module: {
rules: [
{
test: /\.css$/,
use: [
"vue-style-loader",
{
loader: "css-loader",
options: { sourceMap: true }
}
]
},
{
test: /\.s[ac]ss$/,
use: [
"vue-style-loader",
{
loader: "css-loader",
options: { sourceMap: true }
},
{
loader: "sass-loader",
options: {
prependData: `
@import "./src/assets/styles/_main.scss";
`
}
}
]
}
]
}
});

Isi pada webpack.prod.js sama seperti webpack.dev.js hanya aja perbedaannya di sini adalah kita melakukan minification ke dalam file HTML utama. Untuk dokumentasi lebih jelasnya dapat dilihat di sini.

Terlihat pada output, filename berubah menjadi [name].[hash].bundle.js. Ini merujuk pada 2 entry point yang terdapat pada webpack.common.js yaitu main dan vendor, jadi nanti keluaran file javascript di dalam folder dist ada 2, yaitu main.js dan vendor.js. Kita juga melakukan content hash pada output agar setiap kali ada perubahan webpack langsung mengetahuinya dan membuat file untuk di-cache yang baru.

Setelah ini, kita akan melakukan minification terhadap file-file JavaScript dan CSS.

package.json:

{
...,
"scripts": {
"serve": "webpack-dev-server --config webpack.dev.js --open",
"build": "webpack --config webpack.prod.js"
},
...
}

Pada package.json, kita melakukan perubahan terhadap command “serve” dan “build”. Command tersebut memerintahkan untuk memakai konfigurasi sesuai dengan file webpack yang telah kita definisikan sebelumnya.

Minification Terhadap JavaScript dan CSS

Minification adalah proses menghapus semua karakter yang tidak diperlukan yang ada di dalam kode kita. Karakter yang dimaksud adalah white space, new line, comment dan block delimiter. Contoh hasil dari minification:

Langsung saja kita masukkan command

npm i mini-css-extract-plugin optimize-css-assets-webpack-plugin -D

lalu tambahkan plugin pada webpack.prod.js

...
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = merge(common, {
...,
optimization: {
minimizer: [
...,
new OptimizeCssAssetsPlugin()
]
},
plugins: [
new MiniCssExtractPlugin({ filename: "[name].[hash].css" }),
...
],
module: {
rules: [
{
test: /\.s[ac]ss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "sass-loader",
options: {
prependData: `
@import "./src/assets/styles/_main.scss";
`
}
}
]
}
]
},
...
});

Terlihat selain menambahkan plugin, penulis juga mengubah vue-style-loader menjadi MiniCssExtractPlugin.loader. Dokumentasi lebih lengkap dapat ditemukan di sini.

Selain itu, penulis juga menambahkan OptimizeAssetsPlugin pada minimizer agar css yang telah diekstrak oleh MiniCssExtractPlugin dapat dilakukan minification.

Jika kita melakukan command “build”, nanti akan terbuat css yang telah dilakukan minification. Berikut hasilnya:

Tetapi, anehnya main.js yang dari awal telah ter-minification kini berubah menjadi biasa

Maka dari itu, kita harus menambahkan plugin TerserPlugin ke dalam webpack.prod.js. TerserPlugin sendiri telah terinstall di dalam node_modules sehingga kita tidak perlu menginstallnya lagi lewat npm. TerserPlugin berguna untuk me-minify file JavaScript.

Tambahkanlah TerserPlugin ke dalam webpack.prod.js

...
const TerserPlugin = require("terser-webpack-plugin");
module.exports = merge(common, {
...,
optimization: {
minimizer: [
...,
new TerserPlugin()
]
},
...
});

Lalu file JavaScript akan otomatis ter-minify kembali.

Clean Webpack Plugin

Kali ini kita akan menginstall plugin yang akan menghapus semua yang ada di dalam folder dist sebelum melakukan command “build”. Bila kita lihat sekarang, folder dist mempunyai banyak isi. Berikut contoh isi di dalam folder dist

Setiap kali kita melakukan “build”, webpack akan mem-bundle file baru dengan content hash yang berbeda-beda. Maka dari itu kita memerlukan clean webpack plugin agar folder dist kita selalu bersih dari file-file yang sudah lama tidak digunakan.

Langsung saja install

npm i clean-webpack-plugin

lalu masukkan potongan kode ini ke dalam webpack.prod.js

...const { CleanWebpackPlugin } = require("clean-webpack-plugin");...module.exports = merge(common, {
...,
plugins: [
...,
new CleanWebpackPlugin()
],
...
});

Setelah itu jalankan command “build”. Hasil keluarannya kira-kira seperti ini

Sekarang, file yang ada di dalam dist tidak akan sebanyak seperti sebelumnya.

Sampai pada titik ini Anda telah mengkonfigurasi file sass/scss, gambar, svg, font. Anda juga telah melakukan minification terhadap file-file HTML, CSS dan JavaScript sehingga pada mode production ukuran file akan jauh lebih kecil dibandingkan mode development.

Sekian tutorial webpack — vue js. Saya harap tutorial ini membantu Anda.

Credits

Colt Steele, Brandon Wozniewicz

--

--