Gowhich

Durban's Blog

截止目前,以前都是在使用webpack打包react来进行开发,为了跟随技术的步伐,今天来折腾下新版本的新用法

实践环境

1
2
webpack: 4.9.1
react: 16.4.0

1、创建项目并安装

1
mkdir webpack4_react16_reactrouter && cd webpack4_react16_reactrouter
1
npm init -y
1
npm install react react-dom  prop-types
1
npm install webpack webpack-cli html-webpack-plugin clean-webpack-plugin webpack-dev-server eslint eslint-plugin-html eslint-plugin-react babel-eslint eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import babel-core babel-loader babel-plugin-transform-strict-mode babel-plugin-transform-object-assign babel-plugin-transform-decorators-legacy babel-preset-es2015 babel-preset-react babel-preset-stage-0 style-loader css-loader url-loader --save-dev
  • react开发需要用到的
  • babel相关的是用来做es5/es6语法解析的
  • eslint相关的是用来做语言检查的

2、eslint、babel和webpack相关配置

.eslintrc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"env": {
"browser": true,
"node": true,
"es6": true,
"jquery": true
},
"parser": "babel-eslint",
"plugins": [
"react",
"html"
],
"extends": [
"airbnb"
],
"rules": {
"no-underscore-dangle": 0
}
}

.babelrc // 这个文件可以不用加 暂时不起作用

1
2
3
4
5
{
"plugins": [
"transform-es2015-modules-commonjs"
]
}

修改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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

let config = {
mode: 'production',
entry: {
app: ['./src/index.jsx'],
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 8083,
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'React Demo',
filename: './index.html', // 调用的文件
template: './index.html', // 模板文件
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: [
path.resolve(__dirname, 'node_modules'),
],
options: {
plugins: ['transform-async-to-generator', 'transform-strict-mode', 'transform-object-assign', 'transform-decorators-legacy'],
presets: ['es2015', 'react', 'stage-0'],
},
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
],
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader',
],
},
{
test: /\.xml$/,
use: [
'xml-loader',
],
},
],
},
resolve: {
extensions: ['.js', '.jsx'], // 这里是必须要加的,不然默认的值加载['.js','.json']为后缀的文件
},
};

if (process.env.NODE_ENV === 'production') {
config = Object.assign({}, config, {
mode: 'production',
});
} else {
config = Object.assign({}, config, {
mode: 'development',
devtool: 'eval',
});
}

module.exports = config;

下面来修改index.js,修改index.js为index.jsx
src/index.jsx

1
2
3
4
5
6
7
8
import React from 'react';
import ReactDOM from 'react-dom';
import AppComponent from './components/AppComponent';

ReactDOM.render(
(<AppComponent>React Demo</AppComponent>),
document.getElementById('root'),
);

添加src/components/AppComponent.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from 'react';
import PropTypes from 'prop-types';

class AppComponent extends React.Component {
constructor(props, context) {
super(props, context);

this.state = {};
}

render() {
return (
<div>{this.props.children}</div>
);
}
}

AppComponent.propTypes = {
children: PropTypes.node.isRequired,
};

export default AppComponent;

修改index.html,这个只是作为一个模板来使用,具体的后期复杂逻辑,以后的文章分享

1
2
3
4
5
6
7
8
9
<!doctype html>
<html>
<head>
<title></title>
</head>
<body>
<div id="root"></div>
</body>
</html>

项目目录最终的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── components
│ │ └── AppComponent.jsx
│ ├── data.xml
│ ├── demo-image.png
│ ├── font.woff2
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ ├── glyphicons-halflings-regular.woff2
│ ├── index.css
│ ├── index.jsx
│ └── print.js
└── webpack.config.js

运行开发环境的命令

1
npm run start 

执行后,会看到页面展示React Demo,代表我们的程序加好了,之后可以直接进行相关的开发

1
npm run build // 打包
1
npm run build:package // 压缩打包

上面两个都会直接生成dist文件夹,然后里面会生成需要部署的所有文件

项目地址

https://github.com/durban89/webpack4-react16-demo.git

里面有很多细节是在本博客没有的 ,可以自己看下,不懂的可以加群交流。

1、导出

1
mysqldump -u root -h 127.0.0.1 -p 库名称 > 文件名称.sql # 之后是要输入密码的别忘记了

1
mysqldump -u root -h 127.0.0.1 -p gowhich > gowhich_dump.sql # 之后是要输入密码的别忘记了

2、导入

登录mysql创建数据库

1
mysql -u root -h 127.0.0.1 -p # 之后是要输入密码的别忘记了
1
create databases gowhich # 如果你已经有了自己想要导入的库的话,就不需要这一步了

创建完库之后退出
执行

1
mysqldump -u root -h 127.0.0.1 -p 库名称 < 文件名称.sql # 之后是要输入密码的别忘记了

1
mysqldump -u root -h 127.0.0.1 -p gowhich < gowhich_dump.sql # 之后是要输入密码的别忘记了

登录mysql进行数据导入操作

1
2
3
4
mysql -u root -h 127.0.0.1 -p # 之后是要输入密码的别忘记了
source gowhich_dump.sql # 这一步是非常重要的一步
show database; # 查看数据库
show tables; # 查看数据库表

MySQL导入数据库失败的解决方法
参考链接:http://www.chinastor.com/a/jishu/mysqlbf/0G3GV2014.html

使用React做开发,经常会写一些符合自己项目需求的lib库,但是通常用的都是ES6的语法,没办法,谁叫我喜欢这中写代码的方式呢,但是其他同事不会写怎么办,但是又急于要一个跟我写的一模一样的UI,怎么办。我也没办法呀,于是网站找了一圈也只是具体的如何打包,但是具体到如何使用还是有很大的区别的,虽然我也找到了具体的解决办法,但是还是有区别于正常的调用方式
希望懂的认识可以共同探讨

1、创建并初始化项目

1
2
3
mkdir webpack4-library && cd webpack4-library
npm init -y
npm install webpack webpack-cli eslint eslint-plugin-html eslint-plugin-react babel-eslint eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import babel-loader babel-plugin-transform-object-assign babel-plugin-transform-decorators-legacy babel-preset-react babel-preset-stage-0 style-loader css-loader url-loader -D

创建webpack配置文件webpack.config.jswebpack.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
/**
* @author durban.zhang
* @date 2018-05-31
*/

const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
devtool: 'source-map',
entry: path.join(__dirname, 'src/index.js'),
output: {
filename: 'Popbox.min.js',
library: 'Popbox',
libraryTarget: 'umd',
umdNamedDefine: true,
},
module: {
rules: [{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: [
path.resolve(__dirname, 'node_modules')
],
options: {
plugins: ['transform-async-to-generator', 'transform-strict-mode', 'transform-object-assign', 'transform-decorators-legacy'],
presets: ['es2015', 'react', 'stage-0'],
},
},{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
exclude: [
path.resolve(__dirname, 'node_modules')
],
}]
},
plugins: [
new webpack.ProvidePlugin({
Promise: 'es6-promise',
}),
new webpack.DefinePlugin({
'global.GENTLY': false,
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
new webpack.optimize.OccurrenceOrderPlugin(),
],
};

src/index.js 这里js文件就是React项目里面的自己写的lib库,直接拿过来就好了。

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
* @author durba.zhang xxx@xxx
*/
import './styles/index.css';

import tanchuangPng from './images/tanchuang.png';

class Box {
constructor(options) {
this.containerObj = $('.pop-container');
this.options = Object.assign({}, {
title: '提示',
text: '',
}, options);

this.parent = $('<div class="pop-container"></div>');

if (this.containerObj.length) {
this.containerObj.remove();
}
}

init() {
const {
middleBtnText,
} = this.options;

let {
confirmBtnText,
cancelBtnText,
} = this.options;

if (!confirmBtnText) {
confirmBtnText = '确定';
}

if (!confirmBtnText) {
cancelBtnText = '取消';
}

let conText = '';
if (Object.prototype.hasOwnProperty.call(this.options, 'text') &&
this.options.text) {
conText = this.options.text;
}

const $overlayContainer = $('<div class="pop-overlay"></div>');
const $divContainer = $('<div class="pop-alert"></div>');
const $imgContainer = $(`<div class="pop-logo"><img src=${tanchuangPng} width=100 height=100 /></div>`);
const $messageContainer = $('<div class="pop-info"></div>');

const $conContainer = $('<p class="pop-text"></p>');
$conContainer.append(conText);

let $confirmbtnContainer;
if (Object.prototype.hasOwnProperty.call(this.options, 'confirmBtnLink') &&
this.options.confirmBtnLink) {
$confirmbtnContainer = $(`<div class="pop-horizal-box pop-top-border" style="line-height:28px"><a href="${this.options.confirmBtnLinkUrl}" class="btn btn-default confirm-btn">${confirmBtnText}</button></div>`);
} else {
$confirmbtnContainer = $(`<div class="pop-horizal-box pop-top-border"><button class="btn btn-default confirm-btn">${confirmBtnText}</button></div>`);
$confirmbtnContainer.on('click', this.confirmHandle.bind(this));
}

let $middlebtnContainer;
if (Object.prototype.hasOwnProperty.call(this.options, 'middleBtnLink') &&
this.options.middleBtnLink) {
$middlebtnContainer = $(`<div class="pop-horizal-box pop-top-border" style="border-top:none"><a style="padding-top:10px" href="${this.options.middleBtnLinkUrl}" class="btn btn-default confirm-btn">${middleBtnText}</button></div>`);
} else {
$middlebtnContainer = $(`<div class="pop-horizal-box pop-top-border" style="border-top:none"><button class="btn btn-default confirm-btn">${middleBtnText}</button></div>`);
$middlebtnContainer.on('click', this.middleHandle.bind(this));
}

const $cancelbtnContainer = $(`<div class="pop-horizal-box no-bottom-border"><button class="btn btn-default cancel-btn">${cancelBtnText}</button></div>`);
$cancelbtnContainer.on('click', this.cancelHandle.bind(this));

$messageContainer.append($conContainer);
if (!this.options.hideConfirmBtn) {
$messageContainer.append($confirmbtnContainer);
}

if (this.options.middleBtnShow) {
$messageContainer.append($middlebtnContainer);
}

if (!this.options.hideCancelBtn) {
if (this.options.hideConfirmBtn) {
$cancelbtnContainer.css({
'border-top': '1px solid #f1f1f1',
});
}

$messageContainer.append($cancelbtnContainer);
}

$divContainer.append($messageContainer);
this.parent.append($overlayContainer);
this.parent.append($divContainer);
this.parent.append($imgContainer);

$('body').append(this.parent);
this.containerObj = $('.pop-container');
}

confirmHandle() {
this.closeBoxHandle();
if (Object.prototype.hasOwnProperty.call(this.options, 'confirmFunc') &&
this.options.confirmFunc) {
this.options.confirmFunc();
}
}

cancelHandle() {
this.closeBoxHandle();
if (Object.prototype.hasOwnProperty.call(this.options, 'cancelFunc') &&
this.options.cancelFunc) {
this.options.cancelFunc();
}
}

middleHandle() {
this.closeBoxHandle();
if (Object.prototype.hasOwnProperty.call(this.options, 'middleFunc') &&
this.options.middleFunc) {
this.options.middleFunc();
}
}

closeBoxHandle() {
console.log(this.containerObj);
this.containerObj.remove();
}
}

class Popbox {
static pop(options, func) {
const box = new Box(options, func);
box.init();
}

static closePop() {
$('.pop-container').remove();
}
}

export default Popbox;

src/index.css

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*覆层*/

.overlay-component-bg {
position: fixed;
width: 100%;
height: 100%;
bottom: 0;
left: 0;
visibility: hidden;
z-index: 10;
background: rgba(0, 0, 0, 0);
-webkit-transition: all .2s;
-moz-transition: all .2s;
-ms-transition: all .2s;
-o-transition: all .2s;
transition: all .2s;
}

.overlay-bg-show {
background: rgba(0, 0, 0, 0.3);
visibility: visible;
}

/* request loading */

.request-loading {
position: fixed;
height: 60px;
top: 50%;
left: 50%;
text-align: center;
width: 60px;
background: rgba(0, 0, 0, 0.3);
visibility: visible;
border-radius: 5px;
z-index: 5000;
margin-left: -30px;
}

.pop-container .pop-overlay {
background-color: rgba(0, 0, 0, .4);
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 1000;
position: fixed;
}

.pop-container .pop-alert {
display: block;
width: 280px;
min-height: 100px;
z-index: 2000;
background: 0 0;
top: 50%;
left: 50%;
position: fixed;
border-radius: 5px;
margin-left: -140px;
margin-top: -100px;
}

.pop-container .pop-logo {
position: fixed;
top: 50%;
z-index: 30001;
left: 50%;
margin-left: -50px;
margin-top: -150px;
}

.pop-container .pop-info {
display: block;
width: 100%;
min-height: 100px;
background: #fff;
border-radius: 5px;
padding-top: 55px;
}

.pop-container .pop-info .pop-text {
text-align: center;
padding-left: 15px;
padding-right: 15px;
padding-bottom: 10px;
margin-bottom: 10px;
font-size: 16px;
}

.pop-container .pop-info .pop-top-border {
border-top: 1px solid #f1f1f1;
}

.pop-container .pop-info .pop-horizal-box {
height: 40px;
border-bottom: 1px solid #f1f1f1;
text-align: center;
}

.pop-container .pop-info .no-bottom-border {
border-bottom: none
}

.pop-info .pop-horizal-box .confirm-btn {
height: 100%;
border: none;
width: 100%;
box-shadow: none;
background: #fff;
color: #43bae9;
font-size: 15px;
outline: none;
}

.pop-info .pop-horizal-box .cancel-btn {
height: 100%;
border: none;
width: 100%;
box-shadow: none;
background: #fff;
color: #43bae9;
font-size: 15px;
outline: none;
}

index.html

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
<html>
<head>
<meta charset=UTF-8>
<meta http-equiv=X-UA-Compatible>
<meta name=format-detection content="telephone=no">
<meta name=viewport content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<title>Popbox Test</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="./dist/Popbox.min.js"></script>
</head>
<body>
<div>Popbox</div>
<script>
$(() => {
window.Popbox.default.pop({
text: '这个是一个提示',
confirmBtnText: '联系客服',
cancelBtnText: '好的,我知道了',
confirmFunc: () => {
console.log('asda');
},
});
});
</script>
</body>
</html>

项目目录结构

1
2
3
4
5
6
7
8
9
10
11
12
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── images
│ │ └── tanchuang.png
│ ├── index.js
│ ├── lib
│ │ └── Util.js
│ └── styles
│ └── index.css
└── webpack.config.js

打开index.html是不是运行后没有./dist/Popbox.min.js这个文件,没关系,执行下面的命令

1
npx webpack

npx - 是node本身提供的一个功能,需要的具体了解的可以百度或者Google

再打开看看

目前仅适用于app web端,你可以不用使用我写的lib,但是方法是一样的。
提示
注意看package.json,里面的版本号很重要,不同的版本可能会导致不同的异常,可能你就要重新埰坑了。

1
2
3
4
Demo环境
mac os
npm - 6.0.1
node - v8.9.4

项目地址:https://github.com/durban89/webpack4-library

webpack-dev-server 为开发人员提供了一个简单的 web 服务器,并且能够实时重新加载(live reloading)。让我们设置以下:

1
npm install --save-dev webpack-dev-server

修改配置文件,告诉开发服务器(dev server),在哪里查找文件: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
61
62
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
mode: 'development',
entry: {
app: ['./src/index.js'],
print: ['./src/print.js'],
},
devtool: 'eval',
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 8083,
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Webpack-输出管理'
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
]
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader',
]
},
{
test: /\.xml$/,
use: [
'xml-loader',
]
}
],
}
};

让我们添加一个 script 脚本,可以直接运行开发服务器(dev server):
package.json

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
{
"name": "webpack4-demo",
"version": "1.0.0",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack-dev-server --open"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"clean-webpack-plugin": "^0.1.19",
"css-loader": "^0.28.11",
"csv-loader": "^2.1.1",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"style-loader": "^0.21.0",
"webpack": "^4.9.1",
"webpack-cli": "^2.1.4",
"webpack-dev-server": "^3.1.4",
"xml-loader": "^1.2.1"
},
"dependencies": {
"lodash": "^4.17.10"
}
}

现在,我们可以在命令行中运行 npm start,就会看到浏览器自动加载页面。如果现在修改和保存任意源文件,web 服务器就会自动重新加载编译后的代码。试一下!

webpack-dev-server 带有许多可配置的选项。转到[相关文档(https://webpack.docschina.org/configuration/dev-server)]以了解更多。

以上配置告知 webpack-dev-server,在 localhost:8083 下建立服务,将 dist 目录下的文件,作为可访问文件。

这里的配置只是一个非常简答的,如果遇到复杂点的项目可能要做些更多的配置,比如在使用react-router的情况下,这种情况下可能会由于路由的问题导致g更复杂的情况,针对此类的的文章后面跟大家进行分享。

体验环境
mac os
npm - 6.0.1
node - v8.9.4

项目地址:https://github.com/durban89/webpack4-demo

我们在 index.html 文件中手动引入所有资源,然而随着应用程序增长,并且一旦开始对文件名使用哈希(hash)]并输出多个 bundle,手动地对 index.html 文件进行管理,一切就会变得困难起来。然而,可以通过一些插件,会使这个过程更容易操控。

首先,让我们调整一下我们的项目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
├── dist
│ ├── 448c34a56d699c29117adc64c43affeb.woff2
│ ├── 84cfb15e659da6455e7ad3a9d702b9c6.png
│ ├── bundle.js
│ ├── fa2772327f55d8198301fdb8bcfc8158.woff
│ ├── index.html
│ └── main.js
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── data.xml
│ ├── demo-image.png
│ ├── font.woff2
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ ├── glyphicons-halflings-regular.woff2
│ ├── index.css
│ ├── index.js
│ └── print.js
└── webpack.config.js

我们在 src/print.js 文件中添加一些逻辑:

src/print.js

1
2
3
export default function printMe() {
console.log('I get called from print.js!');
}

并且在 src/index.js 文件中使用这个函数:src/index.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
import _ from 'lodash';
import './index.css';
import DemoImage from './demo-image.png';
import Data from './data.xml';
import printMe from './print.js';

function component() {
let element = document.createElement('div');
let btn = document.createElement('button');

// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('red-color');

let img = new Image();
img.src = DemoImage;
element.appendChild(img);

console.log(Data);

btn.innerHTML = '点击我并查看控制台!';
btn.onclick = printMe;
element.appendChild(btn);

return element;
}

document.body.appendChild(component());

我们还要更新 dist/index.html 文件,来为 webpack 分离入口做好准备:dist/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!doctype html>
<html>

<head>
<title>输出管理</title>
<script src="./print.bundle.js"></script>
</head>

<body>
<script src="./app.bundle.js"></script>
</body>

</html>

现在调整配置。我们将在 entry 添加 src/print.js 作为新的入口起点(print),然后修改 output,以便根据入口起点名称动态生成 bundle 名称:
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
const path = require('path');

module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
]
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader',
]
},
{
test: /\.xml$/,
use: [
'xml-loader',
]
}
],
}
};

执行 npm run build,然后看到生成如下:

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
$ npm run build

> xxx@xxx build /Users/durban/nodejs/webpack4-demo
> webpack

Hash: 9d8ee08ba9107370fec6
Version: webpack 4.9.1
Time: 3696ms
Built at: 2018-05-27 13:32:23
Asset Size Chunks Chunk Names
84cfb15e659da6455e7ad3a9d702b9c6.png 1.55 MiB [emitted] [big]
fa2772327f55d8198301fdb8bcfc8158.woff 22.9 KiB [emitted]
448c34a56d699c29117adc64c43affeb.woff2 17.6 KiB [emitted]
print.bundle.js 660 bytes 0 [emitted] print
app.bundle.js 76.8 KiB 1, 0 [emitted] app
Entrypoint app = app.bundle.js
Entrypoint print = print.bundle.js
[0] ./src/print.js 83 bytes {0} {1} [built]
[1] ./src/demo-image.png 82 bytes {1} [built]
[2] ./src/data.xml 110 bytes {1} [built]
[6] ./src/glyphicons-halflings-regular.woff 83 bytes {1} [built]
[7] ./src/glyphicons-halflings-regular.woff2 84 bytes {1} [built]
[10] ./node_modules/css-loader!./src/index.css 627 bytes {1} [built]
[11] ./src/index.css 1.05 KiB {1} [built]
[12] (webpack)/buildin/module.js 519 bytes {1} [built]
[13] (webpack)/buildin/global.js 509 bytes {1} [built]
[14] ./src/index.js 654 bytes {1} [built]
+ 5 hidden modules

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
84cfb15e659da6455e7ad3a9d702b9c6.png (1.55 MiB)

WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/

我们可以看到,webpack 生成 print.bundle.js 和 app.bundle.js 文件,这也和我们在 index.html 文件中指定的文件名称相对应。如果你在浏览器中打开 index.html,就可以看到在点击按钮时会发生什么。

但是,如果我们更改了我们的一个入口起点的名称,甚至添加了一个新的名称,会发生什么?生成的包将被重命名在一个构建中,但是我们的index.html文件仍然会引用旧的名字。我们用 HtmlWebpackPlugin 来解决这个问题。

配置HtmlWebpackPlugin
首先安装插件,并且调整 webpack.config.js 文件: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
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
new HtmlWebpackPlugin({
title: '输出管理'
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
]
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader',
]
},
{
test: /\.xml$/,
use: [
'xml-loader',
]
}
],
}
};

在我们构建之前,你应该了解,虽然在 dist/ 文件夹我们已经有 index.html 这个文件,然而 HtmlWebpackPlugin 还是会默认生成 index.html 文件。这就是说,它会用新生成的 index.html 文件,把我们的原来的替换。让我们看下在执行 npm run build 后会发生什么:

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
$ npm run build

> xxx@xxx build /Users/durban/nodejs/webpack4-demo
> webpack

Hash: 0f3c73600a9071697137
Version: webpack 4.9.1
Time: 882ms
Built at: 2018-05-27 13:37:08
Asset Size Chunks Chunk Names
84cfb15e659da6455e7ad3a9d702b9c6.png 1.55 MiB [emitted] [big]
fa2772327f55d8198301fdb8bcfc8158.woff 22.9 KiB [emitted]
448c34a56d699c29117adc64c43affeb.woff2 17.6 KiB [emitted]
print.bundle.js 660 bytes 0 [emitted] print
app.bundle.js 76.8 KiB 1, 0 [emitted] app
index.html 241 bytes [emitted]
Entrypoint app = app.bundle.js
Entrypoint print = print.bundle.js
[0] ./src/print.js 83 bytes {0} {1} [built]
[1] ./src/demo-image.png 82 bytes {1} [built]
[2] ./src/data.xml 110 bytes {1} [built]
[6] ./src/glyphicons-halflings-regular.woff 83 bytes {1} [built]
[7] ./src/glyphicons-halflings-regular.woff2 84 bytes {1} [built]
[10] ./node_modules/css-loader!./src/index.css 627 bytes {1} [built]
[11] ./src/index.css 1.05 KiB {1} [built]
[12] (webpack)/buildin/module.js 519 bytes {1} [built]
[13] (webpack)/buildin/global.js 509 bytes {1} [built]
[14] ./src/index.js 654 bytes {1} [built]
+ 5 hidden modules

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
84cfb15e659da6455e7ad3a9d702b9c6.png (1.55 MiB)

WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
Child html-webpack-plugin for "index.html":
1 asset
Entrypoint undefined = index.html
[0] (webpack)/buildin/module.js 519 bytes {0} [built]
[1] (webpack)/buildin/global.js 509 bytes {0} [built]
+ 2 hidden modules

如果你在代码编辑器中将 index.html 打开,你就会看到 HtmlWebpackPlugin 创建了一个全新的文件,所有的 bundle 会自动添加到 html 中。

如果你想要了解更多 HtmlWebpackPlugin 插件提供的全部功能和选项,那么你就应该多多熟悉 HtmlWebpackPlugin[https://github.com/jantimon/html-webpack-plugin] 仓库。

你还可以看一下 html-webpack-template,除了默认模板之外,还提供了一些额外的功能。

清理 /dist 文件夹

在之前的几篇关于webpack的文章中,会发现/dist 文件夹相当杂乱。webpack 会生成文件,然后将这些文件放置在 /dist 文件夹中,但是 webpack 无法追踪到哪些文件是实际在项目中用到的。

通常,在每次构建前清理 /dist 文件夹,是比较推荐的做法,因此只会生成用到的文件。让我们完成这个需求。

clean-webpack-plugin 是一个比较普及的管理插件,让我们安装和配置下。

配置CleanWebpackPlugin

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

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');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Webpack-输出管理'
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
]
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader',
]
},
{
test: /\.xml$/,
use: [
'xml-loader',
]
}
],
}
};

现在执行 npm run build,再检查 /dist 文件夹。如果一切顺利,你现在应该不会再看到旧的文件,只有构建后生成的文件!

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
$ npm run build

> xxx@xxx build /Users/durban/nodejs/webpack4-demo
> webpack

clean-webpack-plugin: /Users/durban/nodejs/webpack4-demo/dist has been removed.
Hash: 0f3c73600a9071697137
Version: webpack 4.9.1
Time: 887ms
Built at: 2018-05-27 13:44:59
Asset Size Chunks Chunk Names
84cfb15e659da6455e7ad3a9d702b9c6.png 1.55 MiB [emitted] [big]
fa2772327f55d8198301fdb8bcfc8158.woff 22.9 KiB [emitted]
448c34a56d699c29117adc64c43affeb.woff2 17.6 KiB [emitted]
print.bundle.js 660 bytes 0 [emitted] print
app.bundle.js 76.8 KiB 1, 0 [emitted] app
index.html 249 bytes [emitted]
Entrypoint app = app.bundle.js
Entrypoint print = print.bundle.js
[0] ./src/print.js 83 bytes {0} {1} [built]
[1] ./src/demo-image.png 82 bytes {1} [built]
[2] ./src/data.xml 110 bytes {1} [built]
[6] ./src/glyphicons-halflings-regular.woff 83 bytes {1} [built]
[7] ./src/glyphicons-halflings-regular.woff2 84 bytes {1} [built]
[10] ./node_modules/css-loader!./src/index.css 627 bytes {1} [built]
[11] ./src/index.css 1.05 KiB {1} [built]
[12] (webpack)/buildin/module.js 519 bytes {1} [built]
[13] (webpack)/buildin/global.js 509 bytes {1} [built]
[14] ./src/index.js 654 bytes {1} [built]
+ 5 hidden modules

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
84cfb15e659da6455e7ad3a9d702b9c6.png (1.55 MiB)

WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
Child html-webpack-plugin for "index.html":
1 asset
Entrypoint undefined = index.html
[0] (webpack)/buildin/module.js 519 bytes {0} [built]
[1] (webpack)/buildin/global.js 509 bytes {0} [built]
+ 2 hidden modules

体验环境
mac os
npm - 6.0.1
node - v8.9.4

项目地址:https://github.com/durban89/webpack4-demo.git

继续上一篇博文[webpack4 初体验 - 资源管理 - 加载字体]

可以加载的有用资源还有数据,如 JSON 文件,CSV、TSV 和 XML。类似于 NodeJS,JSON 支持实际上是内置的,也就是说 import Data from ‘./data.json’ 默认将正常运行。要导入 CSV、TSV 和 XML,你可以使用 csv-loader 和 xml-loader。让我们处理这三类文件:

1
npm install --save-dev csv-loader xml-loader

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
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
]
},
{
test: /\.(csv|tsv)$/,
use: [
'csv-loader',
]
},
{
test: /\.xml$/,
use: [
'xml-loader',
]
}
],
}
};

给你的项目添加一些数据文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
├── dist
│ ├── 448c34a56d699c29117adc64c43affeb.woff2
│ ├── 84cfb15e659da6455e7ad3a9d702b9c6.png
│ ├── bundle.js
│ ├── fa2772327f55d8198301fdb8bcfc8158.woff
│ ├── index.html
│ └── main.js
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── data.xml
│ ├── demo-image.png
│ ├── font.woff2
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ ├── glyphicons-halflings-regular.woff2
│ ├── index.css
│ └── index.js
└── webpack.config.js

src/data.xml

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>BJ</to>
<from>SH</from>
<heading>Reminder</heading>
<body>Call Durban on Tuesday</body>
</note>

现在,你可以 import 这四种类型的数据(JSON, CSV, TSV, XML)中的任何一种,所导入的 Data 变量将包含可直接使用的已解析 JSON:src/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import _ from 'lodash';
import './index.css';
import DemoImage from './demo-image.png';
import Data from './data.xml';

function component() {
let element = document.createElement('div');

// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('red-color');

let img = new Image();
img.src = DemoImage;
element.appendChild(img);

console.log(Data);

return element;
}

document.body.appendChild(component());

再次重新构建

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
$ npm run build

> xxx@xxx build /Users/durban/nodejs/webpack4-demo
> webpack

Hash: 0325e1f96ed155017d91
Version: webpack 4.9.1
Time: 3802ms
Built at: 2018-05-27 13:16:12
Asset Size Chunks Chunk Names
84cfb15e659da6455e7ad3a9d702b9c6.png 1.55 MiB [emitted] [big]
fa2772327f55d8198301fdb8bcfc8158.woff 22.9 KiB [emitted]
448c34a56d699c29117adc64c43affeb.woff2 17.6 KiB [emitted]
bundle.js 76.6 KiB 0 [emitted] main
Entrypoint main = bundle.js
[0] ./src/demo-image.png 82 bytes {0} [built]
[1] ./src/data.xml 110 bytes {0} [built]
[5] ./src/glyphicons-halflings-regular.woff 83 bytes {0} [built]
[6] ./src/glyphicons-halflings-regular.woff2 84 bytes {0} [built]
[9] ./node_modules/css-loader!./src/index.css 627 bytes {0} [built]
[10] ./src/index.css 1.05 KiB {0} [built]
[11] (webpack)/buildin/module.js 519 bytes {0} [built]
[12] (webpack)/buildin/global.js 509 bytes {0} [built]
[13] ./src/index.js 488 bytes {0} [built]
+ 5 hidden modules

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
84cfb15e659da6455e7ad3a9d702b9c6.png (1.55 MiB)

WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/

当你打开 index.html 并查看开发者工具中的控制台,你应该能够看到你导入的数据被打印在了上面!

在使用 d3 等工具来实现某些数据可视化时,预加载数据会非常有用。我们可以不用再发送 ajax 请求,然后于运行时解析数据,而是在构建过程中将其提前载入并打包到模块中,以便浏览器加载模块后,可以立即从模块中解析数据。

总结

之前几篇webpack资源管理的内容中最出色之处是,以对应的各种方式加载资源,你可以以更直观的方式将模块和资源组合在一起。无需依赖于含有全部资源的 /assets 目录,而是将资源与代码组合在一起。例如,类似这样的结构会非常有用:

1
2
3
4
5
6
7
|– /components
| |– /my-component
| | |– index.jsx
| | |– index.css
| | |– icon.svg
| | |– img.png
-

这种配置方式会使你的代码更具备可移植性,因为现有的统一放置的方式会造成所有资源紧密耦合在一起。假如你想在另一个项目中使用 /my-component,只需将其复制或移动到 /components 目录下。只要你已经安装了任何扩展依赖(external dependencies),并且你已经在配置中定义过相同的 loader,那么项目应该能够良好运行。

但是,假如你无法使用新的开发方式,只能被固定于旧有开发方式,或者你有一些在多个组件(视图、模板、模块等)之间共享的资源。你仍然可以将这些资源存储在公共目录(base directory)中,甚至配合使用 alias 来使它们更方便 import 导入。

体验环境
mac os
npm - 6.0.1
node - v8.9.4

项目地址:https://github.com/durban89/webpack4-demo.git

继续上一篇博文[webpack4 初体验 - 资源管理 - 加载图片]

像字体这样的其他资源如何处理呢?file-loader 和 url-loader 可以接收并加载任何文件,然后将其输出到构建目录。这就是说,我们可以将它们用于任何类型的文件,包括字体。让我们更新 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
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
]
}
],
}
};

在项目中添加一些字体文件:

项目目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
├── dist
│ ├── 84cfb15e659da6455e7ad3a9d702b9c6.png
│ ├── bundle.js
│ ├── index.html
│ └── main.js
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── demo-image.png
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ ├── glyphicons-halflings-regular.woff2
│ ├── index.css
│ └── index.js
└── webpack.config.js

通过配置好 loader 并将字体文件放在合适的地方,你可以通过一个 @font-face 声明引入。本地的 url(…) 指令会被 webpack 获取处理,就像它处理图片资源一样:

src/index.css

1
2
3
4
5
6
7
8
9
10
11
12
@font-face {
font-family: 'index-font';
src: url('./glyphicons-halflings-regular.woff2') format('woff2'), url('./glyphicons-halflings-regular.woff') format('woff');
font-weight: '600';
font-style: normal;
}

.red-color {
color: red;
font-family: 'index-font';
background: url('./demo-image.png');
}

现在让我们重新构建来看看 webpack 是否处理了我们的字体:

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
$ npm run build

> xx@xx build /Users/durban/nodejs/webpack4-demo
> webpack

Hash: 1172ab68582d197a2b60
Version: webpack 4.9.1
Time: 3729ms
Built at: 2018-05-27 13:08:28
Asset Size Chunks Chunk Names
84cfb15e659da6455e7ad3a9d702b9c6.png 1.55 MiB [emitted] [big]
fa2772327f55d8198301fdb8bcfc8158.woff 22.9 KiB [emitted]
448c34a56d699c29117adc64c43affeb.woff2 17.6 KiB [emitted]
bundle.js 76.4 KiB 0 [emitted] main
Entrypoint main = bundle.js
[0] ./src/demo-image.png 82 bytes {0} [built]
[4] ./src/glyphicons-halflings-regular.woff 83 bytes {0} [built]
[5] ./src/glyphicons-halflings-regular.woff2 84 bytes {0} [built]
[8] ./node_modules/css-loader!./src/index.css 627 bytes {0} [built]
[9] ./src/index.css 1.05 KiB {0} [built]
[10] (webpack)/buildin/module.js 519 bytes {0} [built]
[11] (webpack)/buildin/global.js 509 bytes {0} [built]
[12] ./src/index.js 433 bytes {0} [built]
+ 5 hidden modules

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
84cfb15e659da6455e7ad3a9d702b9c6.png (1.55 MiB)

WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/

重新打开 index.html 看看我们的 Hello webpack 文本显示是否换上了新的字体。如果一切顺利,你应该能看到变化。

体验环境
mac os
npm - 6.0.1
node - v8.9.4

项目地址:https://github.com/durban89/webpack4-demo.git

继续上一篇博文[webpack4 初体验 - 资源管理 - 加载CSS]

如果现在我们正在下载 CSS,但是我们的背景和图标这些图片,要如何处理呢?使用 file-loader,我们可以轻松地将这些内容混合到 CSS 中:

1
npm install --save-dev file-loader

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
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
]
}
],
}
};

现在,当你 import DemoImage from ‘./demo-image.png’,该图像将被处理并添加到 output 目录,_并且_ DemoImage 变量将包含该图像在处理后的最终 url。当使用 css-loader 时,如上篇文章所示,你的 CSS 中的 url(‘./demo-image.png’) 会使用类似的过程去处理。loader 会识别这是一个本地文件,并将 ‘./demo-image.png’ 路径,替换为输出目录中图像的最终路径。html-loader 以相同的方式处理

我们向项目添加一个图像,然后看它是如何工作的,你可以使用任何你喜欢的图像:

项目目录结构

1
2
3
4
5
6
7
8
9
10
11
12
├── dist
│ ├── bundle.js
│ ├── index.html
│ └── main.js
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── demo-image.png
│ ├── index.css
│ └── index.js
└── webpack.config.js

src/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import _ from 'lodash';
import './index.css';
import DemoImage from './demo-image.png'

function component() {
let element = document.createElement('div');

// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('red-color');

let img = new Image();
img.src = DemoImage;
element.appendChild(img);

return element;
}

document.body.appendChild(component());

重新构建,并再次打开 index.html 文件

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
$ npm run build

> xx@xx build /Users/durban/nodejs/webpack4-demo
> webpack

Hash: 39cd25fedf5aaf1e45d6
Version: webpack 4.9.1
Time: 3710ms
Built at: 2018-05-27 12:50:13
Asset Size Chunks Chunk Names
84cfb15e659da6455e7ad3a9d702b9c6.png 1.55 MiB [emitted] [big]
bundle.js 76.1 KiB 0 [emitted] main
Entrypoint main = bundle.js
[0] ./src/demo-image.png 82 bytes {0} [built]
[6] ./node_modules/css-loader!./src/index.css 324 bytes {0} [built]
[7] ./src/index.css 1.05 KiB {0} [built]
[8] (webpack)/buildin/module.js 519 bytes {0} [built]
[9] (webpack)/buildin/global.js 509 bytes {0} [built]
[10] ./src/index.js 433 bytes {0} [built]
+ 5 hidden modules

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
84cfb15e659da6455e7ad3a9d702b9c6.png (1.55 MiB)

WARNING in webpack performance recommendations:
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/

如果一切顺利,和 Hello webpack 文本旁边的 img 元素一样,现在看到的图标是重复的背景图片。如果你检查此元素,你将看到实际的文件名已更改为像 84cfb15e659da6455e7ad3a9d702b9c6.png 一样。这意味着 webpack 在 src 文件夹中找到我们的文件,并成功处理过它!

下一步是,压缩和优化你的图像。可以通过 image-webpack-loader 和 url-loader 实现,具体的下次在继续。

体验环境
mac os
npm - 6.0.1
node - v8.9.4

项目地址:https://github.com/durban89/webpack4-demo.git

继续上一篇博文[webpack4 初体验]

加载 CSS
为了从 JavaScript 模块中 import 一个 CSS 文件,你需要在 module 配置中 安装并添加 style-loader 和 css-loader:

1
npm install --save-dev style-loader css-loader

webpack 根据正则表达式,来确定应该查找哪些文件,并将其提供给指定的 loader。在这种情况下,以 .css 结尾的全部文件,都将被提供给 style-loader 和 css-loader。

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.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
}
],
}
};

这使你可以在依赖于此样式的文件中 import ‘./index.css’。现在,当该模块运行时,含有 CSS 字符串的 <style> 标签,将被插入到 html 文件的 <head> 中。

我们尝试一下,通过在项目中添加一个新的 index.css 文件,并将其导入到我们的 index.js 中:

项目目录结构

1
2
3
4
5
6
7
8
9
10
11
├── dist
│ ├── bundle.js
│ ├── index.html
│ └── main.js
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── index.css
│ └── index.js
└── webpack.config.js

src/style.css

1
2
3
.red-color {
color: red;
}

src/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import _ from 'lodash';
import './index.css';

function component() {
var element = document.createElement('div');

// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('red-color');

return element;
}

document.body.appendChild(component());

现在运行构建命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ npm run build

> xx@xx build /Users/durban/nodejs/webpack4-demo
> webpack

Hash: a4ca66fcccee921aa2ec
Version: webpack 4.9.1
Time: 3696ms
Built at: 2018-05-27 12:37:20
Asset Size Chunks Chunk Names
bundle.js 75.7 KiB 0 [emitted] main
Entrypoint main = bundle.js
[4] ./node_modules/css-loader!./src/index.css 189 bytes {0} [built]
[5] ./src/index.css 1.05 KiB {0} [built]
[6] (webpack)/buildin/module.js 519 bytes {0} [built]
[7] (webpack)/buildin/global.js 509 bytes {0} [built]
[8] ./src/index.js 315 bytes {0} [built]
+ 4 hidden modules

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

再次在浏览器中打开 index.html,你应该看到 Hello webpack 现在的样式是红色。要查看 webpack 做了什么,请检查页面(不要查看页面源代码,因为它不会显示结果),并查看页面的 head 标签。它应该包含我们在 index.js 中导入的 style 块元素。

请注意,在多数情况下,你也可以进行 CSS 分离,以便在生产环境中节省加载时间。最重要的是,现有的 loader 可以支持任何你可以想到的 CSS 处理器风格 - postcss, sass 和 less 等。

体验环境
mac os
npm - 6.0.1
node - v8.9.4

项目地址:https://github.com/durban89/webpack4-demo.git

1、创建项目并安装webpack

1
2
3
mkdir webpack4-demo && cd webpack4-demo
npm init -y
npm install webpack webpack-cli --save-dev
1
2
3
4
5
webpack4-demo
|- package.json
|- index.html
|- /src
|- index.js

src/index.js

1
2
3
4
5
6
7
8
9
10
function component() {
var element = document.createElement('div');

// Lodash
element.innerHTML = _.join(['Hello', 'webpack'], ' ');

return element;
}

document.body.appendChild(component());

index.html

1
2
3
4
5
6
7
8
9
10
<!doctype html>
<html>
<head>
<title>起步</title>
<script src="https://unpkg.com/xx@xx"></script>
</head>
<body>
<script src="./src/index.js"></script>
</body>
</html>

我们还需要调整 package.json 文件,以便确保我们安装包是私有的(private),并且移除 main 入口。这可以防止意外发布你的代码。
package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.0.1",
"webpack-cli": "^2.0.9"
},
"dependencies": {}
}

2、创建一个打包文件

首先,我们稍微调整下目录结构,将“源”代码(/src)从我们的“分发”代码(/dist)中分离出来。“源”代码是用于书写和编辑的代码。“分发”代码是构建过程产生的代码最小化和优化后的“输出”目录,最终将在浏览器中加载:

1
2
3
4
5
6
webpack4-demo
|- package.json
|- /dist
|- index.html
|- /src
|- index.js

要在 index.js 中打包 lodash 依赖,我们需要在本地安装 library:

1
npm install --save lodash

现在,在我们的脚本中 import lodash:
src/index.js

1
2
3
4
5
6
7
8
9
10
11
12
import _ from 'lodash';

function component() {
var element = document.createElement('div');

// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');

return element;
}

document.body.appendChild(component());

现在,由于通过打包来合成脚本,我们必须更新 index.html 文件。因为现在是通过 import 引入 lodash,所以将 lodash <script> 删除,然后修改另一个 <script> 标签来加载 bundle,而不是原始的 /src 文件:

1
2
3
4
5
6
7
8
9
10
11
12
<!doctype html>
<html>

<head>
<title>起步</title>
</head>

<body>
<script src="main.js"></script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
$ npx webpack
Hash: 7262ef43d0038d60faef
Version: webpack 4.9.1
Time: 3375ms
Built at: 2018-05-27 12:07:49
Asset Size Chunks Chunk Names
main.js 70 KiB 0 [emitted] main
Entrypoint main = main.js
[1] (webpack)/buildin/module.js 519 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] ./src/index.js 255 bytes {0} [built]
+ 1 hidden module

在浏览器中打开 index.html,如果一切访问都正常,你应该能看到以下文本:’Hello webpack’。

ES2015 中的 import 和 export 语句已经被标准化。虽然大多数浏览器还无法支持它们,但是 webpack 却能够提供开箱即用般的支持。

事实上,webpack 在幕后会将代码“转译”,以便旧版本浏览器可以执行。如果你检查 dist/main.js,你可以看到 webpack 具体如何实现,这是独创精巧的设计!除了 import 和 export,webpack 还能够很好地支持多种其他模块语法,更多信息请查看模块 API。

注意,webpack 不会更改代码中除 import 和 export 语句以外的部分。如果你在使用其它 ES2015 特性,请确保你在 webpack 的 loader 系统中使用了一个像是 Babel 或 Bublé 的转译器

3、创建webpack配置文件

在 webpack 4 中,可以无须任何配置使用,然而大多数项目会需要很复杂的设置,这就是为什么 webpack 仍然要支持 配置文件。这比在终端(terminal)中手动输入大量命令要高效的多,所以让我们创建一个取代以上使用 CLI 选项方式的配置文件

1
2
3
4
5
6
7
webpack4-demo
|- package.json
|- webpack.config.js
|- /dist
|- index.html
|- /src
|- index.js

webpack.config.js

1
2
3
4
5
6
7
8
9
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};

编译下看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ npx webpack --config webpack.config.js
Hash: b983ef9ac0012695b0e5
Version: webpack 4.9.1
Time: 3369ms
Built at: 2018-05-27 12:09:40
Asset Size Chunks Chunk Names
bundle.js 70 KiB 0 [emitted] main
Entrypoint main = bundle.js
[1] (webpack)/buildin/module.js 519 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] ./src/index.js 255 bytes {0} [built]
+ 1 hidden module

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

4、NPM 脚本配置
考虑到用 CLI 这种方式来运行本地的 webpack 不是特别方便,我们可以设置一个快捷方式。在 package.json 添加一个 npm 脚本(npm script):
package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"name": "webpack4-demo",
"version": "1.0.0",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"css-loader": "^0.28.11",
"style-loader": "^0.21.0",
"webpack": "^4.9.1",
"webpack-cli": "^2.1.4"
},
"dependencies": {
"lodash": "^4.17.10"
}
}

现在,可以使用 npm run build 命令,来替代我们之前使用的 npx 命令。注意,使用 npm 的 scripts,我们可以像使用 npx 那样通过模块名引用本地安装的 npm 包。这是大多数基于 npm 的项目遵循的标准,因为它允许所有贡献者使用同一组通用脚本(如果必要,每个 flag 都带有 –config 标志)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ npm run build

> xx@xx build /Users/durban/nodejs/webpack4-demo
> webpack

Hash: b983ef9ac0012695b0e5
Version: webpack 4.9.1
Time: 350ms
Built at: 2018-05-27 12:10:14
Asset Size Chunks Chunk Names
bundle.js 70 KiB 0 [emitted] main
Entrypoint main = bundle.js
[1] (webpack)/buildin/module.js 519 bytes {0} [built]
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] ./src/index.js 255 bytes {0} [built]
+ 1 hidden module

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

// 重点
通过向 npm run build 命令和你的参数之间添加两个中横线,可以将自定义参数传递给 webpack,例如:npm run build – –colors。

整个体验下来还可以,后面继续体验,最后的目录结果如下

1
2
3
4
5
6
7
8
9
10
11
├── dist
│ ├── bundle.js
│ ├── index.html
│ └── main.js
├── index.html
├── package-lock.json
├── package.json
├── src
│ └── index.js
├── webpack-demo
└── webpack.config.js

体验环境
mac os
npm - 6.0.1
node - v8.9.4

项目地址:https://github.com/durban89/webpack4-demo.git

0%