Memahami Webpack tidak sesulit memahami Wanita (Part IV)

Minifying, Splitting, Cleaning, Separating CSS Webpack Build

I Putu Alfred Crosby
6 min readJul 24, 2016

Wah gak nyangka sudah jauh banget tutorial kita. Sekarang kita akan coba bagaimana minifiying koding kita seminim mungkin. Baik, sesuai janji di awal artikel kita akan menggunakan react-js. Sekarang coba kita pasang reactjs dulu ya 😎

Minifying

npm install react --save

Gak pakai react-dom? Hmm, kita akan fokus bagaimana meminimalisir size bukan fokus bagaimana koding reactjs saat ini.

Setelah terinstall kita require dulu reactnya paling atas di index.js

app/index.js

require('react');...

Ok, masih ES5 😞 Gak apa, coba kita jalankan perintah untuk build file index.js kita.

$ npm run build

Daaaaaaan hasilnya:

Jreeeng, belum koding sampai 100 baris sudah 143kB 😅. Harusnya gak kaya gitu kan. Nah sekarang bagaimana caranya kita convert kode kita ke ukuran yang lebih kecil tanpa menghilangkan makna-makna sakral di dalamnya?

Cara paling mudah dengan menambahkan flag ini di file package.json :

"build": "webpack --optimize-minimize"// atau bisa lebih singkat lagi gunakan ini (pilih salah satu)"build": "webpack -p"

p artinya = optimize minimize. Nah kalau teman-teman coba jalankan pasti akan muncul pesan warning dari Uglify karena kita tidak mengatur konfigurasi Uglify. Coba kita sembunyikan warning dari uglify sebentar hehehe 🤗

libs/parts.js

exports.minify = function() {
return {
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
}
}

webpack.config.js

...case 'build':
config = merge(
common,
{
devtool: 'source-map'
},
parts.cssLoader(PATH.app),
parts.minify()
);
break;
...

Dan coba dijalankan npm run build yang sudah ditambahkan argumen optimize minimize.

Lumayan 42.1 kB 🤔

Dari 143kB jadi sekarang sudah 42.1kB, tapi harusnya masih bisa dikurangi lagi ukurannya. Karena kita belum koding sampai 100 baris 🤔

Uglify itu mempunyai fitur yang disebut mangling, fitur ini mengurangi nama variable atau function biasanya menjadi satu karakter saja. Tapi terkadang kita harus hati-hati, karena bisa saja fitur ini malah merusak program kita.

Sekarang kita mulai masuk ke reactjs, Reactjs ternyata bergantung pada process.env.NODE_ENV untuk mengoptimisasi ukuran build nya. Jika dalam mode production reactjs akan men-disable beberapa fitur check seperti: property-check, yang pastinya akan mengurangi ukuran file kita nanti. Nah, sekarang bagaimana caranya kita memberitahu reactjs bahwa kita menggunakan mode production di dalam webpack? Caranya dengan menggunakan fitur webpack DefinePlugin().

Mari buka file parts.js dan tambahkan part baru seperti dibawah ini:

libs/parts.js

...exports.definePlugin = function(key, value) {
const env = {};
env[key] = JSON.stringify(value);

return {
plugins: [
new webpack.DefinePlugin(env)
]
}
}

webpack.config.js

...case 'build':
config = merge(
common,
{
devtool: 'source-map'
},
parts.cssLoader(PATH.app),
parts.minify(),
parts.definePlugin('process.env.NODE_ENV', 'production')
);
break;
...

Coba dijalankan lagi npm run build-nya

Jreeeng. Lumayan 23.9kB 😎

Ternyata konfigurasi NODE_ENV berpengaruh juga dengan ukuran file 🤔. Sekarang file production kita masih single file. app.js masih include dengan react, bagaimana caranya memisahkan file app.js kita dengan file vendor lainnya? Dan juga kita akan menambahkan hash pada nama file untuk caching di browser.

Splitting

Teknologi ini bernama bundle-splitting, kita bisa mengatur bundle agar berisi file dari vendor saja. Untuk memisahkan bundle caranya adalah seperti ini:

webpack.config.js

...const common = {
entry: {
app: PATH.app,
vendor: ['react']
},
output: {
path: PATH.build,
filename: '[name].js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Belajar Webpack'
})
]
};
...

Nah, sekarang kita sudah punya dua buah entry atau disebut entry-chunks, jadi pada output, filename akan otomatis menjadi app.js dan vendor.js. Coba kita jalankan npm run build.

Hmm, something went wrong.

Hmm 🤔, ada sesuatu yang janggal. Kita sudah pisahkan tapi kenapa file app.js kita masih 23.9kB.

Ternyata walaupun sudah di-chunk, app.js masih berisi reactjs di dalamnya. Bagaimana solusinya? Webpack menyediakan plugin untuk kasus ini yaitu CommonsChunkPlugin(). Mari kita tambahkan part baru lagi pada parts.js

libs/parts.js

...exports.chunkPlugin = function(options) {
const entry = {};
entry[options.name] = options.entries;

return {
entry: entry,
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: [options.name, 'manifest']
})
]
};
}

Lalu HAPUS entry vendor pada webpack.config.js dan panggil part baru yang kita buat.

webpack.config.js

...const onst common = {
entry: {
app: PATH.app,
vendor: ['react'] // hapus ini
},
...}// Panggil chunkPlugin yang baru kita buatswitch(process.env.npm_lifecycle_event) {
case 'build':
config = merge(
common,
{
devtool: 'source-map'
},
parts.cssLoader(PATH.app),
parts.minify(),
parts.definePlugin('process.env.NODE_ENV', 'production'),
parts.chunkPlugin({
name: 'vendor',
entries: ['react']
})

);
break;

Setelah selesai jalankan perintah npm run build, dan akhirnya file berhasil dipisahkan.

Kini app.js menjadi 4.28kB

Hashing

Sekarang kita akan memanfaatkan hashing di webpack. Webpack menyediakan beberapa placeholder yang kita bisa manfaatkan. Ketika build berubah, otomatis hash akan berubah juga. Jadi ketika browser melakukan request, file yang sama tidak akan di-request lagi, hanya file yang berubah akan di-request oleh browser. Kita buka file webpack.config.js dan ubah sesuai kode berikut:

webpack.config.js

...const common = {
entry: {
app: PATH.app
},
output: {
path: PATH.build,
filename: '[name].[chunkhash].js',
chunkFilename: '[chunkhash].js'

},
...
}

Jalankan npm run build:

Nama file dengan hash

Clean the build

Sip, sekarang kita akan membersihkan folder build setiap kita menjalankan npm run build, bisa saja dilakukan dengan cara rm -rf ./build lalu jalankan npm run build. Tapi kita akan melakukannya dengan cara elegan yaitu dengan sebuah modul npm clean-webpack-plugin 😎

Mari install dulu modul nya.

npm install clean-webpack-plugin --save-dev

Kemudian tambahkan part baru.

libs/parts.js

const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
...exports.cleanBuild = function(path) {
return {
plugins: [
new CleanWebpackPlugin([path], {
root: process.cwd()
})
]
}
}

webpack.config.js

switch(process.env.npm_lifecycle_event) {
case 'build':
config = merge(
common,
{
devtool: 'source-map'
},
parts.cssLoader(PATH.app),
parts.minify(),
parts.definePlugin('process.env.NODE_ENV', 'production'),
parts.chunkPlugin({
name: 'vendor',
entries: ['react']
}),
parts.cleanBuild(PATH.build)
);
break;
...}

Sip, disana kita memasukkan argumen letak folder build. Jadi sekarang file konfigurasi webpack kita sudah lebih layak. Tapi masih ada yang major-issue, css masih inline dengan javascript dan ini bisa menyebabkan Flash of Unstyled Content. Solusinya, kita harus mengekstrak file css ke file berbeda.

Separating CSS build

Untuk mengekstrak css kita membutuhkan npm modul yaitu ExtractTectWebpackPlugin. Mari kita install dulu plugin nya.

npm install extract-text-webpack-plugin --save-dev

Plugin ini tidak bisa digunakan dengan HMR, tapi jangan takut, karena kita akan menggunakan ini hanya pada mode production. Oke, lanjut kita tambah part baru pada parts.js

libs/parts.js

const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
...exports.extractCSS = function(paths) {
return {
module: {
loaders: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style', 'css?modules&sourceMap'),
include: paths
}
]
},
plugins: [
new ExtractTextPlugin('[name].[chunkhash].css')
]
}
}

Kemudian pada file webpack.config.js cssLoader() kita ganti dengan extractCSS().

webpack.config.js

switch(process.env.npm_lifecycle_event) {
case 'build':
config = merge(
common,
{
devtool: 'source-map'
},
p̶a̶r̶t̶s̶.̶c̶s̶s̶L̶o̶a̶d̶e̶r̶(̶P̶A̶T̶H̶.̶a̶p̶p̶)̶ // hapus ini
parts.extractCSS(PATH.app), // ganti dengan ini
parts.minify(),
parts.definePlugin('process.env.NODE_ENV', 'production'),
parts.chunkPlugin({
name: 'vendor',
entries: ['react']
})
);
break;

Oke, jika sudah diganti coba di build ulang - npm run build !!😎

Ukuran file kita semakin kecil dan kecil 😎

Sip. File css sudah dipisahkan dan build kita semakin bagus dan layak. Tapi koding kita masih terdapat error ya jika dijalankan file hasil build-nya 🙁 Kalau kita ingin coba, coba di comment dulu require(‘react’) pada file index.js lalu di build ulang. (sampai saat ini saya belum tahu penyebabnya mungkin ada yang bisa bantu?)😔

Kesimpulan

Akhirnya artikel ke-empat dari series ini dapat saya selesaikan. Kita sudah berhasil mengimplementasikan semua plugin-plugin yang disediakan webpack. Dan masih banyak yang harus dibahas stay tune ya guys. 😉

Source code dapat dilihat disini, (pada branch build-webpack)

😍

Jika artikel ini bermanfaat jangan lupa di-share dan klik heart icon-nya.

Artikel Lainnya

Artikel ini merupakan bagian dari Memahami Webpack tidak sesulit memahami Wanita the Series.

Memahami Webpack tidak sesulit memahami Wanita the Series

--

--