As you get more deeply involved in front-end development, webpack
becomes unavoidable. Here, I’ll note the method for creating a static site with about 20 pages using webpack
.
In the project root:
$ npm init -y (Generate configuration file)
$ npm install --save-dev webpack webpack-cli
The --save-dev
option means that the information about the installed package will be recorded in package.json
.
Options
--save-dev
Used when installing tools for application development--save
Used when installing components needed for the application itself to runAfter installing webpack
, your package.json
will have a record like this:
{
"name": "e-learning-general",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10"
}
}
Apparently, webpack
can also be used to create common elements like header
and footer
, but I couldn’t figure out how to do it effectively, so I decided to build with pug
and output to the public
folder for publishing.
So, for now, let’s forget about webpack
and install the necessary pug
and pug-cli
:
$ npm install --save-dev pug pug-cli
Next, create a public
folder for publishing and a src
folder to store the HTML layouts at the project root.
$ mkdir public src
Create a layout
folder directly under src
to store the pug
files.
$ mkdir src/layout
Now that we’ve done this, we can write with pug
. Using pug
’s Includes
, you can componentize headers, footers, and other parts. In my case, I put common components in the _common
folder. The folder structure looks like this:
layout/_common
|- _partials folder (Common files such as header and footer)
|- _baseof.pug (Base pug file)
/user
/money
Next, create the base _baseof.pug
:
block pagedata
doctype html
html(lang="ja")
head
meta(charset="utf-8")
meta(http-equiv="X-UA-Compatible" content="IE=edge")
meta(name="viewport" content="width=device-width, initial-scale=1.0")
link(href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet")
title #{pageTitle} | Sample
body
include ./_partials/_header ← Common part
block main ← Content for each page goes here
include ./_partials/_footer ← Common part
block pagejs ← JavaScript for each page
Now that we’ve come this far, all that’s left is to create the common parts in pug
and then create each page. Here’s what creating a user screen looks like. First load the baseof.pug
file, then build from there. Setting a path
variable for the static site directory is convenient.
//- Load template
extend ../_common/_baseof
//- Page-specific settings
append pagedata
- var pageTitle= "About this site";
- var path = '../';
//- Page-specific JavaScript
append pagejs
script(src=`${path}main.js`)
//- Page content
block main User will be displayed here
After creating the layout with pug
, we need to create a script to output it to the public
folder.
The location doesn’t matter, but for now, let’s create sample.sh
at the project root.
$ touch sample.sh
Write a script to build pug
in sample.sh
:
#sample.sh
npx pug src/layout/user/*.pug --pretty --out public/terms
Now let’s try running the script:
% sh sample.sh
If it builds correctly, you should see HTML in the public
folder. That completes the HTML part.
If you use webpack-dev-server
, changes to files will be reflected immediately, so let’s install it:
$ npm install --save-dev webpack-dev-server
Create a webpack.config.js
to enable webpack-dev-server
:
$ touch webpack.config.js
Here’s the basic form including webpack-dev-server
and entry points:
module.exports = {
entry: './src/index.js',
output: {
path: `${__dirname}/public`,
filename: 'main.js'
},
devServer: {
contentBase: `${__dirname}/public`,
},
};
Edit package.json
to make webpack-dev-server
easy to start.
Also, add a build command
:
"scripts": {
"start": "webpack-dev-server --open",
"build": "webpack --config webpack.config.js"
},
Create index.js
in the src
folder to serve as the entry point:
$ touch src/index.js
An entry point
is the starting file when bundling.
// index.js
console.log('This is the entry point')
Now that we’ve done this, let’s start webpack-dev-server
.
First, build to output main.js
:
$ npm run build
Start webpack-dev-server
:
$ npm start
If the screen displays correctly, check the console in the developer tools.
You should see This is the entry point displayed.
Install css-loader
, style-loader
, sass-loader
, and node-sass
which is needed to compile scss
:
$ npm install --save-dev webpack webpack-cli css-loader style-loader sass-loader node-sass
After installation, specify the test files and use loaders to apply in the module-rules parameter
of webpack.config.js
.
Loaders are applied from right to left. In this case, since it’s a bit line-broken, they’re applied from the bottom up. First, sass-loader
compiles sass
to css using node-sass
, then css-loader
bundles it, and finally style-loader
applies it to insert the css into the js file.
module: {
rules: [
{
test: /\.css|scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
],
},
],
}
Let’s try with style.scss
like this:
body {
background-color: red;
}
Import this style.scss
as a module in the entry point index.js
:
import './assets/scss/style.scss';
$ npm start
If the body
is red, it’s a success. You should see the color change immediately when you update the scss
.
$ npm install --save normalize.css
Import normalize.css
:
import 'normalize.css'
Since normalize.css
is officially published through npm, just install it as is.
If you build, you can confirm that normalize.css
has been added to main.js
:
$ npm run build
In production, you might want to compress source code or remove unnecessary console.log
statements before building. For this, we use webpack-merge
.
Create the following files at the project root:
$ touch webpack.base.js webpack.development.js webpack.production.js
Install webpack-merge
:
$ npm install --save-dev webpack webpack-cli webpack-merge
First, let’s set up the common configuration:
// Common settings: webpack.base.js
module.exports = {
entry: './src/index.js',
output: {
path: `${__dirname}/public`,
filename: 'main.js'
},
devServer: {
contentBase: `${__dirname}/public`,
},
module: {
rules: [
{
test: /\.css|scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
],
},
],
}
};
Next is the webpack.development.js
configuration. Since we’re in development, it’s better to be able to check sourcemaps:
const merge = require('webpack-merge');
const base = require('./webpack.base.js');
module.exports = merge(base, {
mode: 'development',
devtool: 'eval-source-map',
})
For production, just setting webpack’s mode
to production
will automatically handle compression. If you need detailed settings, configure them with plugins as needed. Below, we’re using terser-webpack-plugin
to prevent outputting console.log:
const merge = require('webpack-merge');
const base = require('./webpack.base.js');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = merge(base, {
mode: 'production',
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
terserOptions: {
compress: {drop_console: true}
}
})],
}
})
Now that we’ve split the development and production settings using webpack-merge
, let’s specify these settings in package.json
:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --open-page -config webpack.development.js",
"build": "webpack --config webpack.production.js && sh sample.sh"
},
With this, npm start
will launch with development settings, and npm run build
will build with production settings.
The end.