Oke, lalu bagaimana cara kita membuat atau menyusun aplikasi web yang lengkap?
Yang kita inginkan adalah web yang memiliki tampilan juga.
Dengan Express, ada 2 jalan yang tersedia:
- Membuat backend (REST API) dahulu lalu membuat frontend (HTML, CSS, JS) dalam sistemnya masing-masing, ataupun dengan urutan sebaliknya
- Membuat backend dan frontend sekaligus dalam sistem yang sama dan pada waktu yang sama
Di sini sebagai permulaan, kita bisa langsung terjun ke cara kedua.
Kita bisa meng-generate aplikasi Express lebih instan dengan Express application generator.
Terima kasih express-generator!
$ npm i -g express-generator
$ express app-name
$ cd app-name && npm installSetelah setup dan instalasi, lalu jalankan:
$ npm start
> expressjs-web@1.0.0 start /home/yourname/3-EXPRESSJS-WEB
> node ./bin/wwwMaka aplikasi berjalan di URL localhost:3000:
$ curl localhost:3000
<!DOCTYPE html><html><head><title>Express</title><link rel="stylesheet" href="/stylesheets/style.css"></head>
<body><h1>Express</h1><p>Welcome to Express</p></body></html>%Jalankanlah web-nya di browser.
Di terminal juga akan terlihat log route apa saja yang diakses oleh user:
GET / 200 201.808 ms - 170
GET / 200 19.655 ms - 170
GET /stylesheets/style.css 200 5.881 ms - 111
GET /favicon.ico 404 31.150 ms - 1745
GET / 200 9.486 ms - 170
...Bukan sulap, bukan sihir!
Ketika melihat struktur aplikasi yang dibuat melalui generator, tentu mayoritas orang akan kaget.
Ini apa aja???
.
├── app.js
├── bin
│ └── www
├── package.json
├── package-lock.json
├── public
│ ├── images
│ ├── javascripts
│ └── stylesheets
│ └── style.css
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.jade
├── index.jade
└── layout.jadeMari kita telaah satu-satu.
Mulai dari package.json ya:
...
"scripts": {
"start": "node ./bin/www"
},
...Di sini diketahui bahwa aplikasi dijalankan pertama kali melalui file ./bin/www yang mana juga adalah file JavaScript tapi tanpa ekstensi .js.
Pada bagian awal kode-nya, terlihat bahwa www mengimpor file ../app (atau ../app.js tanpa ekstensi) sebagai server aplikasi utama.
Tujuan file www ini hanyalah untuk konfigurasi semata.
// Module dependencies
var app = require('../app');
var debug = require('debug')('app:server');
var http = require('http');
// Get port from environment and store in Express
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
// Create HTTP server
var server = http.createServer(app);
// Listen on provided port, on all network interfaces
server.listen(port);- Dependency di-load
- Konfigurasi variabel
PORT - Membuat HTTP server dari dependency
- Menjalankan server tersebut dengan port yang sudah diatur
Sisanya hanyalah function untuk berbagai kondisi tertentu.
Pada aplikasi Express umumnya ada berbagai dependency esensial berikut yang mana sebagian juga merupakan plugin atau middleware untuk Express.
...
"dependencies": {
"body-parser": "~1.18.2",
"cookie-parser": "~1.4.3",
"debug": "~2.6.9",
"express": "~4.15.5",
"jade": "~1.11.0",
"morgan": "~1.9.0",
"serve-favicon": "~2.4.5"
}body-parser- mem-parsing HTTP request body yang berasal dari client ke servercookie-parser- mem-parsing HTTP cookie headerdebug- utility untuk debuggingjade(sekarang juga disebutpug) - view/template engine untuk menyusun merender HTML yang modular di server, terdapat beberapa file ekstensi.jadedi project kitamorgan- plugin untuk logging HTTP requestserve-favicon- plugin untuk menyajikan favicon dari server
Untuk lebih lengkapnya bisa lihat satu-satu di npmjs.com.
Mulai dari sinilah struktur project hasil generator sangat berperan.
.
├── app.js # aplikasi utama
├── bin
│ └── www # konfigurasi utama
├── package.json
├── package-lock.json # hanya untuk mengunci versi dependency
├── public # berbagai file static yang disajikan oleh app.js
├── routes # berbagai route yang diimpor dan dijalankan oleh app.js
└── views # berbagai tampilah HTML yang di-render oleh JadeSetelah mengetahui hal penting dari apa yang sudah di-generate, sambil melihat app.js secara hati-hati, cara kerja utama aplikasinya kurang lebih:
bin/wwwmengonfigurasi untuk menjalankanapp.js
var app = require('../app');
var debug = require('debug')('app:server');
var http = require('http');app.jsmengatur aplikasi secara keseluruhan yang diawali dengan mengimpor berbagai dependency yang sudah diinstal
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');- Mengimpor module route yang ada di
routes
var index = require('./routes/index');
var users = require('./routes/users');- Meng-instantiate objek
appdariexpress
var app = express();- Mengatur view engine dengan Jade
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');- Menggunakan berbagai plugin yang diperlukan
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));- Menggunakan module route yang sudah diimpor agar bisa diakses melalui HTTP request
app.use('/', index);
app.use('/users', users);- Menangkap error jika perlu dengan bantuan file
views/error.jadeuntuk menampilan error dengan format HTML
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});- Mengekspor aplikasi ini agar bisa digunakan oleh
bin/www
module.exports = app;Di dalam file routes/index.js, bisa kita lihat bahwa ada pengaturan route di path /.
Hasilnya akan me-render halaman index (dari views/index.jade) yang di dalam app.js diproses oleh plugin Jade yang sudah digunakan.
Parameter kedua dalam function res.render akan dimasukkan ke dalam template tersebut.
Barulah module route ini diekspor untuk digunakan oleh app.js.
routes/index.js:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;Sedangkan template-nya akan mengambil variabel yang diberikan melalui parameter di atas.
views/index.jade:
extends layout
block content
h1= title
p Welcome to #{title}Mungkin Jade ini agak mengagetkan karena yang tadinya HTML ada berbagai tag pembuka / penutup, di Jade semuanya hilang, lebih simple, tapi mengandalkan indentasi.
Singkatnya, file index.jade tersebut akan di-render sebagai HTML ke client setelah proses res.render terjadi.
Yang mana index.jade itupun mengandalkan file layout.jade untuk membungkusnya dengan semua elemen HTML yang esensial (doctype, html, head, body) dan menempatkan isinya di block content:
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block contentSilakan diresapi secara perlahan.
Esensi prinsip ini berlaku juga untuk file routes/users.js, walaupun tidak me-render halaman, namun hanya data saja:
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});Express dapat memuat berbagai file static apapun yang bukan merupakan program.
app.use(express.static(path.join(__dirname, 'public')));Di sini berarti apapun yang ada di folder public, maka akan bisa diakses sesuai dengan path-nya masing-masing:
/public/imagesbisa diakses melaluilocalhost:3000/images/public/javascriptsbisa diakses melaluilocalhost:3000/javascripts/public/stylesheetsbisa diakses melaluilocalhost:3000/stylesheets
Berarti kurang lebih aplikasi Express yang dapat memuat backend dan frontend sekaligus secara lengkap memerlukan dan menjalankan:
- Konfigurasi
- Impor berbagai module
- Routes
- View
- Sajian file static
Selebihnya bisa dioprek dulu, nanti juga mengerti.
Terdapat live code via Glitch di https://glitch.com/~static-express yang dapat dilihat hasilnya di https://static-express.glitch.me dan source code-nya di https://glitch.com/edit/#!/static-express.
