การพัฒนาเว็บยุคใหม่ ภาค 2 - Multiple Entry Points
บทความนี้เป็นภาคต่อของ การพัฒนาเว็บยุคใหม่ ภาค 1 - Webpack ซึ่งเราจะพูดถึงการ Transpile JavaScript มากกว่า 1 ไฟล์
จากบทความภาคที่แล้ว เราได้ลอง Transpile JavaScript แค่ไฟล์เดียว ซึ่งเวลาใช้งานจริง ใน 1 เว็บไซต์ไม่ได้มี JavaScript แค่ไฟล์เดียวแน่นอน (ยกเว้นว่าจะเป็นเว็บเล็ก ๆ)
Entry Point คืออะไร
Entry Point คือไฟล์ JavaScript หลักที่ Webpack จะเริ่มต้นประมวลผล ซึ่งก็คือไฟล์ JavaScript ที่เราสั่งให้ Webpack ทำการ Transpile ในบทความที่แล้ว ปรกติแล้วเว็บในแต่ละหน้าหากมีการใช้ JavaScript มักจะมีอยู่ 3 ไฟล์ คือ
- ไฟล์แรกสำหรับ Logic เฉพาะหน้านั้น ๆ
- ไฟล์สองสำหรับ Layout/Template ของหน้านั้น ๆ
- ไฟล์สามสำหรับแชร์ Code ที่ใช้บ่อยมากกว่าหนึ่งหน้า
หากเราต้องการมากกว่า 1 Entry Point เรามีอยู่ 2 ทางเลือก คือ
- รัน Webpack หนึ่งครั้งต่อหนึ่ง Entry Point
- เขียน Script สำหรับ List รายการ Entry Point ทั้งหมดแล้วส่งเข้า Webpack
ปัญหาของวิธีแรกคือ ไม่ยืดหยุ่น เนื่องจากเราต้องมากำหนดชื่อไฟล์แต่ละไฟล์เอง ดั่งนั้น วิธีที่สองเป็นทางเลือกที่ดีที่สุด
สร้าง Script สำหรับรัน Webpack
จริง ๆ แล้ว Webpack ไม่ได้มีแค่คำสั่งที่เราเคยใช้ก่อนหน้านั้น แต่ Webpack มี Module ของ Node.js ให้เราเรียกใช้งานได้ด้วย เราจะใช้ Module ตัวนี้เพื่อเขียน Script สำหรับ List รายการ Entry Points ทั้งหมดที่เรามี แล้วส่งให้ Webpack
ก่อนอื่น เราต้องออกแบบโครงสร้างของแฟ้มใน Project ก่อนเพื่อให้ง่ายต่อการจัดการ ตัวอย่างโครงสร้างที่ผมใช้
.
|-- ...
|-- assets
| |-- src
| | |-- entry1.js
| | |-- entry2.js
| | `-- ...
| `-- webpack.base.conf.js
|-- ...
|-- wwwroot
| `-- assets
| `-- js
| |-- entry1.js
| |-- entry2.js
| `-- ....
`-- package.json
แฟ้ม wwwroot/assets
คือแฟ้มที่เราจะเก็บ Output ของ Webpack ด้วยโครงสร้างนี้ เราสามารถ List รายการ Entry Point ทั้งหมดจากแฟ้ม assets/src
แค่แฟ้มเดียวได้เลย และยังสามารถลบแฟ้ม wwwroot/assets
ทั้งแฟ้มก่อนที่จะรัน Webpack เพื่อลบไฟล์ทั้งหมดจากการรันครั้งที่แล้วได้ด้วย
เสร็จแล้ว ให้สร้างไฟล์ JavaScript อันใหม่ขึ้นมา ไฟล์นี้จะเป็นตัวเก็บ Config ต่าง ๆ ของ Script ที่เรากำลังจะสร้าง ซึ่งควรจะอยู่ที่เดียวกันกับ Script นั้น ตัวอย่าง
'use strict'
const path = require('path')
const projectPath = path.dirname(__dirname)
const sourcePath = path.join(__dirname, 'src')
const outputPath = path.join(projectPath, 'wwwroot', 'assets')
module.exports = {
projectPath,
sourcePath,
outputPath
}
ต่อมา เราต้องแก้ไฟล์ Config ของ Webpack เพื่อกำหนดรายการ Entry Points ตัวอย่าง
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
'use strict'
const path = require('path')
const glob = require('glob')
const config = require('./config')
function getEntryPoints() {
return new Promise((resolve, reject) => {
glob(path.join(config.sourcePath, '*.js'), (err, matches) => {
if (err) {
reject(err)
} else {
resolve(matches)
}
})
})
}
module.exports = async function () {
let entryPoints = (await getEntryPoints()).reduce((obj, file) => {
obj[path.parse(file).name] = file
return obj
}, {})
return {
entry: entryPoints,
output: {
path: config.outputPath,
filename: path.join('js', '[name].js')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['babel-preset-env']
}
}
}
]
}
}
}
บรรทัดที่ 4 เป็นการเรียกใช้ Module glob ซึ่งเราต้องติดตั้งเพิ่ม ส่วนบรรทัดที่ 5 เป็นการเรียกใช้ Config ที่เราพึ่งสร้างเมื่อกี้ (ผมตั้งชื่อว่า config.js
ซึ่งอยู่ในแฟ้มเดียวกันกับ
Config ของ Webpack)
ขั้นตอนสุดท้าย สร้าง Script สำหรับรัน Webpack ตัวอย่าง
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'use strict'
const rimraf = require('rimraf')
const webpack = require('webpack')
const config = require('./config')
const webpackConfig = require('./webpack.base.conf')
rimraf(config.outputPath, async err => {
if (err) {
throw err
}
webpack(await webpackConfig(), (err, stats) => {
if (err) {
throw err
}
let result = stats.toString({colors: true})
console.log(result)
})
})
บรรทัดที่ 6 เป็นการเรียกใช้ Config ของ Webpack ที่เราพึ่งแก้ไขไปเมื่อกี้ ส่วนบรรทัดที่ 8 เป็นการสั่งลบแฟ้มที่เก็บ Output ทั้งแฟ้มก่อนการรัน Webpack
การรัน Script ที่เราเขียนก็เหมือนกับการรัน Node.js ทั่วไป ตัวอย่าง
node assets/build.js
เช่นเคย เราสามารถใส่คำสั่งนี้ไว้ใน package.json
เพื่อย่นเวลาการพิมพ์คำสั่งได้
บทส่งท้าย
พอเราสามารถ Transpile ได้มากกว่า 1 ไฟล์ เราก็สามารถที่จะเริ่มใช้ Webpack อย่างจริงจังใน Project ได้แล้ว ในภาคต่อไปของบทความ จะเป็นการ Import ไฟล์อื่น ๆ เข้ามาในไฟล์ JavaScript เพื่อใช้งานไฟล์นั้น ๆ ซึ่งไม่จำกัดว่าจะต้องเป็นไฟล์ JavaScript เช่น เราสามารถ Import ไฟล์ PNG หรือ CSS เข้ามาได้