Vincec's Dimension

Nodejs - Webpack3 学习笔记

Word count: 2,806 / Reading time: 18 min
2018/06/15 Share

Benefits

  • Require assets, which are loaded when needed
  • Code splitting
  • Transformations

Start and generate bundle.js

1. Install and init within the project folder.

1
npm init

New package.json file is generated as example

1
2
3
4
5
6
7
8
9
10
11
{
"name": "webpack-overview",
"version": "1.0.0",
"description": "test",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Vince",
"license": "ISC"
}

2. Install the webpack

  • At the same tome to save it as flag into the json dependencies for all folders
1
npm install webpack @3 .6 .0--save - dev
  • Run install again for other folders
1
npm install

3. Create bundle.js

Create a index.js, we aim to get it as bundle.js

1
node_modules /.bin/webpack index.js bundle.js

4. Use more optimized way

  • Moving index.js to ./src/

  • Create webpack config file webpack.config.js in the root /. This way can keep the file more organized

1
2
3
4
5
6
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js"
}
};
  • Run in termanial with webpack config file
1
node_modules /.bin/webpack
  • For specific the dist folder of bundle.js, change webpack.config.js
1
2
3
4
5
6
7
8
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.join(_dirname, "dist")
}
};

5. Use bundle.js in index.html

1
<script src = "./dist/bundle.js" ></script>

Set npm build command with webpack

  • Edit package.json
1
2
3
4
5
6
7
8
9
10
11
{
"name": "webpack-overview",
"version": "1.0.0",
"description": "test",
"main": "index.js",
"scripts": {
"build": "webpack"
},
"author": "Vince",
"license": "ISC"
}
  • Use build command to run the webpack
1
npm run build

Add watch when each save happen

  • Edit package.json
1
2
3
4
5
6
7
8
9
10
11
12
{
"name": "webpack-overview",
"version": "1.0.0",
"description": "test",
"main": "index.js",
"scripts": {
"build": "webpack",
"watch": "webpack --w"
},
"author": "Vince",
"license": "ISC"
}
  • run the watch command, get new bundle real time
1
npm run watch

Webpack Loaders

  • Perform transformations on files
  • Help load files and images
  • Deal with dialects

Babel-loader

Transpiling JSX or ES6 – Babel –> plaint js

Config webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const path = require("path")
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.join(_dirname, "dist")
},
module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env"]
}
}
}]
}
}

npm install loader

Install babel-loader babel-core and babel-preset-env by npm

1
npm install babel-loader babel-core babel-preset-env --save-dev

Create config file .babeirc for babel

Create .babeirc file in root

1
2
3
{
"presets": ["env"]
}

npm build command (es6 to es5)

use build command to run the webpack

1
npm run build

Babel-loader enable stage-0 features on tc39 proposals

  • On terminal
1
2
#from stage 0 to 3
npm install babel-preset-stage-0 --save-dev
  • Edit webpack.config.js
1
2
3
options: {
presets: ["env", "stage-0"];
}
  • Edit .babeirc file in root
1
2
3
{
"presets": ["env", "stage-0"]
}
  • Use npm build
1
npm run build

Babel-preset-react

  • install babel-preset-react, react, react-dom, and serve
1
2
3
4
5
npm install babel-preset-react --save-dev
npm install react react-dom --save

#install serve
sudo npm install serve -g
  • Edit index.js
1
2
3
4
5
6
import React from 'react'
import ReactDOM from 'react-dom`

const MyComponent = () => <h1>Webpack &amp; React</h1>

ReactDOM.render(<MyComponent />, document.getElementById('react-container'))
  • Edit index.html
1
2
<!-- add -->
<div id="react-container"></div>
  • Edit package.json add serve
1
2
3
4
"scripts":{
"build": "webpack && serve",
"watch": "webpack --w"
}
  • Run build command
1
npm run build
  • Edit webpack.config.js
1
2
3
options: {
presets: ["env", "stage-0", "react"];
}
  • Edit .babeirc file in root
1
2
3
{
"presets": ["env", "stage-0", "react"]
}

load style with react way

load css

  • Edit index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react'
import ReactDOM from 'react-dom`
import './style.css'

const Message extends React.Component {
render(){
return (
<div>
<h1>{this.props.title}</h1>
<p>{this.props.message}</p>
</div>
)
}
}

ReactDOM.render(<Message title="Email Alex" message="Email him" />, document.getElementById('react-container'))
  • Create a new file style.css on ./src/ folder with simple style
1
2
3
4
h1 {
font-family: Arial;
color: #ff0000;
}
  • install style and other loaders on terminal
1
npm install style-loader css-loader --save-dev
  • Change webpack.config.js with style-loader and css-loader
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
const path = require("path")

module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.join(_dirname, "dist")
},
module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env", "stage-0", "react"]
}
}
}, {
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
]
}]
    }
}
  • npm run command
1
npm run build

load scss

  • Create a new file style.scss on ./src/ folder with simple style
1
2
3
4
5
6
7
$green: #00FF00;
$white: #FFFFFF;

div{
background-color: $green;
color: $white;
}
  • Edit index.js file
1
import './style.scss'
  • install more loaders on terminal
1
npm install sass-loader node-sass --save-dev
  • Change webpack.config.js with scss
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
const path = require("path")

module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.join(_dirname, "dist")
},
module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env", "stage-0", "react"]
}
}
}, {
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
]
}, {
test: /\.scss$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "sass-loader"}
]
}]
    }
}
  • npm run command
1
npm run build

load image

  • Create a new file style.scss on ./src/ folder with simple style
1
2
3
4
5
#image{
background: url('123.png');
height: 900px;
width: 900px;
}
  • install loaders on terminal
1
npm install url-loader file-loader --save-dev
  • Edit index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React from 'react'
import ReactDOM from 'react-dom`
import './style.css'

const Image extends React.Component {
render(){
return (
<div>
<h1>{this.props.title}</h1>
<p>{this.props.caption}</p>
<div id="image"></div>
</div>
)
}
}

ReactDOM.render(<Image title="Title" caption="Caption" />, document.getElementById('react-container'))
  • Change webpack.config.js with image-loader
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
const path = require("path")

module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.join(_dirname, "dist")
},
module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env", "stage-0", "react"]
}
}
}, {
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
]
}, {
test: /\.scss$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "sass-loader"}
]
}, {
test: /\.jpg$/,
use: [
{loader: "url-loader"}
]
}]
    }
}
  • npm run command
1
npm run build

Webpack-dev-server

  • Node.js Express server
  • webpack-dev-middleware
  • Socket.IO

Dev Server

  • install on terminal
1
npm install webpack-dev-server --save-dev
  • Change webpack.config.js with dev-server
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
const path = require("path")

module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.join(_dirname, "dist")
},

devServer: {
contentBase: path.join(_dirname, "dist"),
port: 8080
},

module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env", "stage-0", "react"]
}
}
}, {
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
]
}, {
test: /\.scss$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "sass-loader"}
]
}, {
test: /\.jpg$/,
use: [
{loader: "url-loader"}
]
}]
    }
}
  • Create a index.html under ./dist/
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>webpack</title>
</head>
<body>
<div id="react-container"></div>
<script src="./bundle.js"></script>
</body>
</html>
  • Add command in package.json
1
2
3
4
5
"scripts": {
"build": "webpack && serve",
"dev": "webpack-dev-server",
"watch": "webpack --w"
}
  • Make some modify in index.js to change the bundle
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
import React from 'react'
import ReactDOM from 'react-dom`
import './style.css'

const Image extends React.Component {
// add the constructor
constructor(props){
super()
this.state = {
title: "Peaks"
}
}
render(){
return ( //change props to state
<div>
<h1>{this.state.title}</h1>
<p>{this.props.caption}</p>
<div id="image"></div>
</div>
)
}
}

//remove the title
ReactDOM.render(<Image caption="Caption" />, document.getElementById('react-container'))
  • npm run dev-server command
1
npm run dev
  • Go to localhost:8080 and each save will show on the browser

Code splitting

  • Create new about.html and about.js in ./src/
    about.html
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>About</title>
</head>
<body>
<div id="react-container"></div>
<script type="text/javascript" src="../build/about.bundle.js"></script>
</body>
</html>

about.js

1
2
3
4
5
6
7
8
9
10
11
12
13
//es6 features, since we only use Component from React and reder from reactDOM
import { Component } from 'react'
import { render } from 'react-dom'

class About extends Component {
render(){
return (
<div> This is info </div>
)
}
}

render(<About />, document.getElementById('react-contianer'))
  • Create new contact.html, contact.js in ./src/
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>Contact</title>
</head>
<body>
<div id="react-container"></div>
<script type="text/javascript" src="../build/contact.bundle.js"></script>
</body>
</html>

contact.js

1
2
3
4
5
6
7
8
9
10
11
12
13
//es6 features, since we only use Component from React and reder from reactDOM
import { Component } from 'react'
import { render } from 'react-dom'

class Contact extends Component {
render(){
return (
<div> Contact to us</div>
)
}
}

render(<Contact />, document.getElementById('react-contianer'))
  • Edit the webpack.config.js with entry and output
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
47
48
49
50
const path = require("path")

module.exports = {
// entry: "./src/index.js",
entry: {
about: "./src/about.js",
contact: "./src/contact.js"
},
output: {
// filename: "bundle.js",
filename: "[name].bundle.js"
path: path.join(_dirname, "dist")
},

devServer: {
contentBase: path.join(_dirname, "dist"),
port: 8080
},

module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env", "stage-0", "react"]
}
}
}, {
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
]
}, {
test: /\.scss$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "sass-loader"}
]
}, {
test: /\.jpg$/,
use: [
{loader: "url-loader"}
]
}]
    }
}
  • npm run command
1
npm run build
  • Can see two bundle create

Plugins – use commons chunk bundle

  • Edit the webpack.config.js
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
47
48
49
50
51
52
53
54
55
const path = require("path")
//add webpack const
const webpack = require("webpack")

module.exports = {
entry: {
about: "./src/about.js",
contact: "./src/contact.js"
},
output: {
filename: "[name].bundle.js"
path: path.join(_dirname, "dist")
},
devServer: {
contentBase: path.join(_dirname, "dist"),
port: 8080
},
module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env", "stage-0", "react"]
}
}
}, {
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
]
}, {
test: /\.scss$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "sass-loader"}
]
}, {
test: /\.jpg$/,
use: [
{loader: "url-loader"}
]
}]
    },
//add plugins
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "commons",
filename: "commons.bundle.js"
})
]
}
  • Edit the about.html and contact.html with common bundle
1
2
3
4
5
<body>
<div id="react-container"></div>
<script type="text/javascript" src="../build/common.bundle.js"></script>
<script type="text/javascript" src="../build/*.bundle.js"></script>
</body>
  • npm run command
1
npm run build

Building Vendor files

  • /src/index.js (only file in src)
1
2
3
4
5
6
7
8
9
10
11
12
import { Component } from 'react'
import { render } from 'react-dom'

class Display extends Component {
render(){
return (
<div> Display index</div>
)
}
}

render(<Display />, document.getElementById('react-contianer'))
  • Modify /webpack.config.js
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
47
48
49
50
51
52
53
54
55
56
57
const path = require("path")
const webpack = require("webpack")

module.exports = {
entry: {
// about: "./src/about.js",
// contact: "./src/contact.js"
vendor: ["react", "react-dom"],
app: "./src/index.js"
},
output: {
filename: "[name].bundle.js"
path: path.join(_dirname, "dist")
},
devServer: {
contentBase: path.join(_dirname, "dist"),
port: 8080
},
module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env", "stage-0", "react"]
}
}
}, {
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
]
}, {
test: /\.scss$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "sass-loader"}
]
}, {
test: /\.jpg$/,
use: [
{loader: "url-loader"}
]
}]
    },
plugins: [
new webpack.optimize.CommonsChunkPlugin({
// name: "commons",
// filename: "commons.bundle.js"
name: "vendor",
filename: "vendor.bundle.js"
})
]
}
  • npm run command
1
npm run build

HTML webpack plugin

  • Install html-webpack-plugin
1
npm install html-webpack-plugin --save-dev
  • Modify /webpack.config.js
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
47
48
49
50
51
52
53
54
55
56
57
const path = require("path")
const webpack = require("webpack")
//add new plugin
const HTMLWebpackPlugin = require("html-webpack-plugin")

module.exports = {
entry: {
vendor: ["react", "react-dom"],
app: "./src/index.js"
},
output: {
filename: "[name].bundle.js"
path: path.join(_dirname, "dist")
},
devServer: {
contentBase: path.join(_dirname, "dist"),
port: 8080
},
module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env", "stage-0", "react"]
}
}
}, {
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
]
}, {
test: /\.scss$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "sass-loader"}
]
}, {
test: /\.jpg$/,
use: [
{loader: "url-loader"}
]
}]
    },
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "vendor.bundle.js"
}),
//new plugin
new HTMLWebpackPlugin()
]
}
  • /src/index.js remain same

  • npm run command

1
npm run build
  • New /dist/index.html generated, with correct order of vendor.bundle.js and app.bundle.js

uglifyjs - Minify, get bundle in oneline

  • Install ulgifyjs-webpack-plugin
1
npm install ulgifyjs-webpack-plugin --save-dev
  • Replace /src/index.js
1
const add = (x, y) => x + y
  • Modify /webpack.config.js
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const path = require("path")
const webpack = require("webpack")
//add uglyify plugin
const UglifyJsPlugin = require("uglifyjs-webpack-plugin")

module.exports = {
// entry: {
// vendor: ["react", "react-dom"],
// app: "./src/index.js"
// },

entry: "./src/index.js",
output: {
filename: "[name].bundle.js"
path: path.join(_dirname, "dist")
},
devServer: {
contentBase: path.join(_dirname, "dist"),
port: 8080
},
module: {
rules: [{
test: /.js$/,
exclude: /(node_modules)/
use: {
loader: "babel-loader",
options: {
presets: ["env", "stage-0", "react"]
}
}
}, {
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
]
}, {
test: /\.scss$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "sass-loader"}
]
}, {
test: /\.jpg$/,
use: [
{loader: "url-loader"}
]
}]
    },
//remove the plugins
plugins: [
// new webpack.optimize.CommonsChunkPlugin({
// name: "vendor",
// filename: "vendor.bundle.js"
// }),
// new HTMLWebpackPlugin()
new UglifyJsPlugin()
]
}
  • npm run command
1
npm run build
  • Check the /dist/main.bundle.js is inlined

  • Show progress in command, edit /package.json

    1
    2
    3
    4
    5
    "scripts": {
    "build": "webpack --progress && serve",
    "dev": "webpack-dev-server",
    "watch": "webpack --w"
    }

Reference

CATALOG
  1. 1. Benefits
  2. 2. Start and generate bundle.js
    1. 2.1. 1. Install and init within the project folder.
    2. 2.2. 2. Install the webpack
    3. 2.3. 3. Create bundle.js
    4. 2.4. 4. Use more optimized way
    5. 2.5. 5. Use bundle.js in index.html
  3. 3. Set npm build command with webpack
  4. 4. Add watch when each save happen
  5. 5. Webpack Loaders
    1. 5.1. Babel-loader
      1. 5.1.1. Config webpack.config.js
      2. 5.1.2. npm install loader
      3. 5.1.3. Create config file .babeirc for babel
      4. 5.1.4. npm build command (es6 to es5)
    2. 5.2. Babel-loader enable stage-0 features on tc39 proposals
    3. 5.3. Babel-preset-react
  6. 6. load style with react way
    1. 6.1. load css
    2. 6.2. load scss
    3. 6.3. load image
  7. 7. Webpack-dev-server
    1. 7.1. Dev Server
  8. 8. Code splitting
  9. 9. Plugins – use commons chunk bundle
  10. 10. Building Vendor files
  11. 11. HTML webpack plugin
  12. 12. uglifyjs - Minify, get bundle in oneline
  13. 13. Reference