目录 § ⇧
- 1. 前置知识 §
- 2. 用到的工具 §
- 3.
webpack功能 §
- 4.
CRM学webpack §
- 4.1. 目标一:用
webpack转译JS §
- 4.2 目标二理解文件名中
hash的用途 §
- 4.3 目标三:用
webpack生成HTML §
- 4.4 目标四:用
webpack引入CSS §
- 4.5 目标五:用
webpack引入SCSS §
- 4.6. 目标六:用
webpack引入LESS 、 Stylus和Postcss §
- 4.7. 目标七:用
webpack引入图片 §
- 4.8. 目标八:用
webpack的 import() 实现懒加载 §
- 4.9. 目标九:部署到
GitHub Pages §
- 5. 从webpack看前端工具的历史 §
- 9. 死掉的前端工具 §
- 9. 和webpack竞争的工具 §
- 9. 基于webpack的工具 §
- 6. 总结 §
- 4.10. 目标十:自己写一个
loader §
- 4.11. 目标十一:自己写一个
plugin §
- 7. 问答 §
- 8. 学英语 §
0.安装webpack
- webpack 的运行,是需要依赖 node.js 的运行环境
- 官网https://webpack.js.org/
- Get Started
- 查看目前有哪几种版本 对应版本号
npm info webpack versions
- 全局安装
npm i -g webpack@4 webpack-cli@3
- 项目文件安装
npm init -y && npm install webpack@4 webpack-cli@3 --save-dev
- 或者
yarn init -y && yarn add webpack@4 webpack-cli@3 webpack-dev-server@3 --dev
- 或者
npm init -y && yarn add webpack@4 webpack-cli@3 webpack-dev-server@3 --dev
- 不可两者都用
实际的版本号是
webpack@4.44.1
webpack-cli@3.3.12
webpack-dev-server@3.11.0
前端工程化的理解
webpack 模块能以各种方式表达它们的依赖关系
ES2015 import 语句
CommonJS require() 语句
AMD define 和 require 语句
css/sass/less 文件中的 @import 语句。
stylesheet url(...) 或者 HTML <img src=...> 文件中的图片链接
- …
1. 前置知识 §
ES6
- let / const / 箭头函数 / … / class / Promise
- 继承 / this / 原型
CSS 语和布局
MVC 概念
- Model / View / Controller /EventHub
工具的使用
- VSCode / WebStorm
- 终端命令行 npm / yarn / http-server / parcel / git
2. 用到的工具 §
webpack@4安装方法见官网Getting Started
- 在
webpack后面加个 @4 即可
- 如果
webpack升级到了5, 思路依然有效
webpack-dev-server
- 用于本地预览
- parcel 不和 webpack 配套
Yarn
正式进入框架阶段
3. webpack功能与使用 §
一个包含前端的项目,里面可能有多个 .js, 多个 .css , 多个静态图片, 多个其他前端资源。
一些 js 资源彼此之前存在依赖关系,当一个页面需要加载多个 .js 的话,也会拖累整个页面的加载速度
为了解决这个问题,webpack 就把各种各样的静态资源,打包成了一个所谓的 assets. 加快浏览器加载
- 转译代码(ES6转为ES5,SCSS转为CSS)
- 构建build
- 代码打包
- 代码压缩
- 代码分析
Vue React Webpack 知识对基础知识的杂糅
使用webpack运行
1
|
mkdir ./src && touch index.html && cd src && touch index.js
|
调用本地局部安装的 webpack
1
|
./node_modules/.bin/webpack --version
|
自动寻找本地文件夹的 webpack
4. CRM学webpack §
- 目标一:用
webpack转译JS
- 目标二:理解文件名中
hash的用途
- 目标三:用
webpack生成HTML
- 目标四:用
webpack引入CSS
- 目标五:用
webpack引入SCSS
- 目标六:用
webpack引入LESS 和 Stylus
- 目标七:部署到
GitHub Pages
- 目标八:用
webpack的 file-loader 引入图片引入图片
- 目标九:用
webpack的 import() 实现懒加载
- 目标十:自己写一个
loader
- 目标十一:自己写一个
plugin
- 目标十二:用
webpack实现模块热替换HMR
- 目标十三:用
webpack引入TypeScript
- 目标十四:用
Flow检查器
- 目标十五:用
webpack引入各大框架Vuw React Electron
4.1. 目标一:用webpack转译JS §
途径
什么是转译JS
- 分析JS代码,并转译成低版本浏览器可以用的JS
./src/x.js export default 'xxx'
./src/index.js import x from './x.js'; console.log(x)
- 项目路径中
npx webpack,查看dist目录中main.js
初始化 webpack.config.js
去除npx webpack的警告:WARNING in configuration The 'mode' option has not been set...
webpack.config.js
1
2
3
4
5
6
7
8
9
10
|
const path = require('path');
module.exports = {
mode: 'development',
entry: './foo.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'foo.bundle.js'
}
};
|
生产模式(production) 开发模式(development)区别
- 在
dist/main.js中,生产模式压缩的代码体积小;开发模式,便于Debug
- 如果暂时没有影响就不用管
- 之后详细说明如何切换两者
webpack 配置 entry 和 output
修改webpack.config.js> module.exports> entry默认入口文件entry: './src/index.js'
1
2
3
4
5
6
7
8
|
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
}
};
|
- 再运行
npx webpack
- 查看
dist路径后多了foo.bundle.js
- 修改
output> filename为main.js
- 手动删除原来的dist路径
- 再运行
npx webpack
- 配置
entry 和 output,会把./src/路径下的JS文件转译后放到dist路径下
- 默认目标路径可以不写
path: path.resolve(__dirname, 'dist')
- 入口和出口的配置
4.2 目标二:理解文件名中hash的用途 §
- 官网webpack->Caching
- 出口的文件名改为
'[name].[contenthash].js'
- 再运行
npx webpack得到main.xxx.js文件名后多了hash值用来HTTP缓存
HTTP响应头中的 Cache-Control
- 设置缓存头
- 点开响应头
Response Headers中的Cache-Control
public, max-age=31536000设置最大缓存一年
- 缓存过期后,再重新请求
HTTP 缓存的意义
- 缓存一年
- 除了
index.html外的资源存储在用户浏览器的缓存中
- 减少连接数,访问时间不用重复下载资源
- 资源的下载速度之间可差百倍
怎么更新JS CSS之类的资源
- 对资源文件内容做一个MD5 文件名后加hash
'[name].[contenthash].js'就是做这个的
- 每次修改文件内容,再次打包,得新到的
main.xxx.js
- 文件内容和文件名有一一对应的关系
- 之前的缓存就没用了
- 浏览器就会更新资源 ,删除原来的缓存
为什么不缓存index.html
- 需要在首页中存储更改hash的文件名
- 通知浏览器其他资源的入口
- 首页一定不能做缓存,或者设置的最大缓存时间不能太长
- 链接到 【HTTP非全解】
dist文件越来越多,在 yarn build时设置自动删除并构建
- 在
package.json> script中设置rm -rf dist && npx webpack
- 可省略
npx,自动寻找webpack,rm -rf dist && webpack
package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
{
"name": "webpack-demo-1",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"dependencies": {
"webpack": "4",
"webpack-cli": "3",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "3",
"webpack-log": "^2.0.0",
"webpack-sources": "^1.4.3"
},
"scripts": {
"build": "rm -rf dist && webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
|
yarn build或者npm run build
webpack.config.js
1
2
3
4
5
6
7
8
9
10
|
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
}
};
|
4.3 目标三:用webpack生成HTML §
之前先用git提交下代码备份
安装HtmlWebpackPlugin
1
2
|
# npm install --save-dev html-webpack-plugin
yarn add html-webpack-plugin --dev
|
配置webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.[contenthash].js'
},
plugins: [new HtmlWebpackPlugin()]
};
|
- 运行
yarn build
- 自动生成一个空的html,自动引入了
index.xxx.js
- dist目录下的文件都是自动生成的,不可手动修改
生成一个html模板
- 新建
./src/assets目录 index.html
- 配置
webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.[contenthash].js'
},
plugins: [new HtmlWebpackPlugin({
title: 'webpack',
// filename: 'test.html',
template: 'src/assets/index.html'
})]
};
|
- 修改
index.html 为常用初始模板,之后配置
- 对应的标签模板
<title><%= htmlWebpackPlugin.options.title %></title>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,viewport-fit=cover">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div></div>
</body>
</html>
|
x.js
index.js
1
2
3
|
import x from './x.js'
console.log('x')
console.log(x)
|
可以实现
- 自动更新html文件名
- 自动使用配置里的title标签
- 自动把引入的js标签放到body底部
要点
- 自动更改文件名
- 插件
HtmlWebpackPlugin 生成 HTML
4.4 目标四:用webpack引入CSS §
webpack 引入模块化 CSS
x.css
1
2
3
|
body {
background: orange;
}
|
x.js
1
2
|
import './x.css'
export default 'xxx'
|
index.js
- 编译css时报错
ERROR in ./src/x.css 1:5.
Module parse failed: Unexpected token (1:5)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file...
需要css-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
21
22
23
24
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.[contenthash].js'
},
plugins: [new HtmlWebpackPlugin({
title: 'webpack',
// filename: 'test.html',
template: 'src/assets/index.html'
})],
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}
};
|
按报错安装所需的工具模块Module not found: Error: Can't resolve 'style-loader'
1
|
yarn add style-loader --dev
|
- 再运行
yarn build
style-loader把css-loader解析的CSS代码放到页面的head > style标签中
- 开发模式下使用,无需用
link标签引入CSS文件
- 没有
Cache-Control做缓存,未部署
x.js观察引入的x.css,之前暂时删掉webpack.config.js的'style-loader',
1
2
3
4
5
6
7
8
9
10
|
import css from './x.css'
console.dir(css)
console.log(css.toString())
/*
export default function printMe() {
console.log('I get called from print.js!');
}
*/
export default 'xxx'
|
cd ..回到上级目录,再运行yarn build
cd dist后,使用hs -c-1查看控制台
使用更方便的webpack-dev-server自动刷新部署代替hs -c-1
1
|
yarn add webpack-dev-server --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
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.[contenthash].js'
},
plugins: [new HtmlWebpackPlugin({
title: 'webpack',
// filename: 'test.html',
template: 'src/assets/index.html'
})],
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}
};
|
package.json
1
2
3
4
5
6
7
8
|
...
"scripts": {
"build": "rm -rf dist && webpack",
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --open",
"watch": "webpack --watch"
},
...
|
- 运行
yarn start
- 或者运行
npm run start
- 访问端口
http://localhost:8080/
- 测试实时更新页面
background: gray;
- 不需要在开发时频繁
yarn build或是手动删除dist
- 不会创建或依赖
dist目录,在内存中运行,自动更新
singletonStyleTag
使用单个的 <style> 标签加载所有css属性,或者是每个css模块一个 <style> 标签
- webpack style-loader singletonStyleTag
- 默认值是
false(每个css模块一个 <style> 标签)
- 默认情况下,每一个css文件会变为一个
<style>标签
- 实际加载中,可能有多个
<style>标签;
- 默认值为
false (而不是原文中说的默认情况下启用此选项)
- 当该值设置为
true 时,那么,原本多个<style>标签会被合并成一个<style>标签
- 官方文档上写的是默认开启,实际上是不开启的
除了用style-loader生成style,也可以吧CSS抽成文件
1
|
yarn add mini-css-extract-plugin --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
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.[contenthash].js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack',
// filename: 'test.html',
template: 'src/assets/index.html'
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css',
ignoreOrder: false,
}),
],
module: {
rules: [
{
test: /\.css$/,
// css-loader
// use: [ 'style-loader', 'css-loader' ]
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
},
'css-loader'
]
}
]
}
};
|
目前实现了
MiniCssExtractPlugin把css-loader解析的CSS代码放到页面的head > link标签中
- 实时生成带
hash的js文件到script标签中,并放在body标签内的最后
- 做
Cache-Control适用于生产环境
要点:引入 css的两种方式
- 开发时可以使用
JS生成style,快速,不需要在dist中生成css文件
- 发布时可以把
CSS抽成带hash文件,可以做缓存
如何做到在开发时用第一种方式
发布时,即在生产环境中,用第二种方式
- 根据模式选择不同的途径
- 生产环境:
yarn build;
- 对应的
package.json中:"build": "rm -rf dist && webpack"
- 做缓存,用
MiniCssExtractPlugin生成link标签
- 引入带
hash的CSS文件
- 插入
head标签
- 开发环境:
yarn start;
- 对应的
package.json中:"start": "webpack-dev-server"
- 不做缓存,用
css-loader生成style标签
- 插入
head标签
终端命令行使用帮助文档webpack --help
- 未全局安装的话用
npx webpack --help
- 设置配置文件
package.json的路径
"build": "rm -rf dist && webpack --config webpack.config.prod.js"
- 意思是,在
build时,不适用默认的配置,而是使用webpack.config.prod.js的配置
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": "webpack-demo-1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"webpack": "4",
"webpack-cli": "3",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "3",
"webpack-log": "^2.0.0",
"webpack-sources": "^1.4.3"
},
"devDependencies": {
"css-loader": "^3.6.0",
"html-webpack-plugin": "^4.3.0",
"mini-css-extract-plugin": "^0.9.0",
"style-loader": "^1.2.1"
},
"scripts": {
"build": "rm -rf dist && webpack --config webpack.config.prod.js",
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server",
"watch": "webpack --watch"
},
}
|
yarn start
- 查看
dist,目录中index.html是否引入了style标签
使用两个 webpack config 文件,切换开发模式
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
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
},
output: {...},
plugins: [
new HtmlWebpackPlugin({...}),
],
module: {
rules: [
{
test: /\.css$/,
// mode: 'development'
// `yarn start`
// css-loader
use: [ 'style-loader', 'css-loader' ]
}
]
}
};
|
- 创建生产环境的
webpack.config.prod.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
|
let HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
},
output: {...},
plugins: [
new HtmlWebpackPlugin({...}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css',
ignoreOrder: false,
}),
],
module: {
rules: [
{
test: /\.css$/,
// mode: 'production'
// `yarn build`
// MiniCssExtractPlugin
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
},
'css-loader'
]
}
]
}
};
|
继承共有属性 webpack.config.base.js
- 配置继承
webpack.config.base.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
let HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.[contenthash].js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack',
template: 'src/assets/index.html'
})
]
};
|
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
|
const path = require('path');
const base = require('./webpack.config.base.js')
module.exports = {
...base,
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
},
mode: 'development',
module: {
rules: [
{
test: /\.css$/i,
// mode: 'development'
// `yarn start`
// css-loader
use: [ 'style-loader', 'css-loader' ]
}
]
}
};
|
webpack.config.prod.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
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const base = require('./webpack.config.base.js')
module.exports = {
...base,
mode: 'production',
plugins: [
...base.plugins,
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css',
ignoreOrder: false,
}),
],
module: {
// ...base.module.rules,
rules: [
{
test: /\.css$/,
// mode: 'production'
// `yarn build`
// MiniCssExtractPlugin
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
},
'css-loader'
]
}
]
}
};
|
yarn build production mode
yarn start development mode
用工具插件webpack-merge实现自动切换
配置分离 生产环境构建
环境变量
webpack 实现了
- 内置
babel-loader转译n个JS文件为1个JS文件
- 用
JS``import CSS,style/css-loader就转译为style标签
- 用
MiniCssExtractPlugin转译n个CSS文件为1个CSS文件
loader vs plugin
loader 和 plugin的区别是
- 翻译一下,
loader是加载器,plugin是插件
loader作用加载文件
plugin作用扩展/加强功能
举例
babel-loader用来加载JS,转移为低版本的JS
style-loader和css-loader用来加载CSS,变为页面中的标签
- new 一个
HtmlWebpackPlugin MiniCssExtractPlugin
- plugins 需要安装后require() loader直接安装依赖使用
搜英文关键词,选择性地CRM
4.5 目标五:用webpack引入SCSS §
将x.css改名为x.scss,在x.js里改为import css from './x.scss'
注意不要覆盖配置中的module
- 在
rules: []里加一句...base.module.rules,
webpack.config.base.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
|
let HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.[contenthash].js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack',
template: 'src/assets/index.html'
})
],
module: {
rules: [
{
test: /\.scss$/i,
use: [
// Creates `style` nodes from JS strings
{
loader: 'style-loader',
options: {
injectType: 'singletonStyleTag'
}
},
// Translates CSS into CommonJS
'css-loader',
// Compiles Scss to CSS
{
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require('dart-sass'),
sassOptions: {
fiber: require('fibers')
}
}
}
]
}
]
}
}
|
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
|
const path = require('path')
const base = require('./webpack.config.base.js')
module.exports = {
...base,
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
},
mode: 'development',
module: {
rules: [
...base.module.rules,
{
test: /\.css$/i,
// mode: 'development'
// `yarn start`
// css-loader
use: [
// Creates `style` nodes from JS strings
base.module.rules[0].use[0],
// Translates CSS into CommonJS
base.module.rules[0].use[1],
]
}
]
}
}
|
webpack.config.prod.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
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const base = require('./webpack.config.base.js')
module.exports = {
...base,
mode: 'production',
plugins: [
...base.plugins,
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css',
ignoreOrder: false,
}),
],
module: {
// ...base.module.rules,
rules: [
{
test: /\.scss$/i,
use: [
// Creates `style` nodes from JS strings
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
},
// Translates CSS into CommonJS
base.module.rules[0].use[1],
// Compiles Scss to CSS
base.module.rules[0].use[2],
]
},
{
test: /\.css$/i,
// mode: 'production'
// `yarn build`
// MiniCssExtractPlugin
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
},
'css-loader'
]
},
]
}
};
|
x.js
1
2
3
4
5
6
7
8
9
10
11
12
|
import './x.scss'
// import css from './x.scss'
// console.dir(css)
// console.log(css.toString())
/*
export default function printMe() {
console.log('I get called from print.js!');
}
*/
export default 'xxx'
|
要点
1
|
yarn add sass-loader sass dart-sass --dev
|
4.6. 目标六:用webpack引入PostCSS、 LESS 和 Stylus §
要点
1
2
3
4
5
|
yarn add less-loader --dev &&
yarn add stylus-loader stylus --dev &&
yarn add postcss-loader --dev &&
yarn add autoprefixer --dev &&
yarn add postcss-cssnext --dev
|
x.js
1
2
3
4
|
import './x.scss'
import './y.less'
import './z.styl'
export default 'xxx'
|
index.js
webpack.config.base.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
|
let HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const styleLoader = {
loader: 'style-loader',
options: {
injectType: 'singletonStyleTag'
}
}
const scssLoader = {
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require('dart-sass'),
sassOptions: {
fiber: require('fibers')
}
}
}
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.[contenthash].js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack',
template: 'src/assets/index.html'
})
],
module: {
rules: [
{
test: /\.css$/i,
// mode: 'development'
// `yarn start`
// css-loader
use: [
// Creates `style` nodes from JS strings
styleLoader,
// Translates CSS into CommonJS
'css-loader',
]
},
{
test: /\.scss$/i,
use: [
// Creates `style` nodes from JS strings
styleLoader,
// Translates CSS into CommonJS
'css-loader',
// Compiles Scss to CSS
scssLoader
]
},
// rules[1]
{
test: /\.less$/i,
loader: [styleLoader, 'css-loader', 'less-loader'] // compiles Less to CSS
}
]
}
};
|
webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
const base = require('./webpack.config.base.js')
module.exports = {
...base,
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
},
mode: 'development',
module: {
rules: [
...base.module.rules,
]
}
};
|
webpack.config.prod.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
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const base = require('./webpack.config.base.js')
const cssLoaderPlugin = {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
},
}
module.exports = {
...base,
mode: 'production',
plugins: [
...base.plugins,
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css',
ignoreOrder: false,
}),
],
module: {
rules: [
// ...base.module.rules,
{
test: /\.css$/i,
// mode: 'production'
// `yarn build`
// MiniCssExtractPlugin
use: [
cssLoaderPlugin,
'css-loader'
]
},
{
test: /\.scss$/i,
use: [
// Creates `style` nodes from JS strings
cssLoaderPlugin,
// Translates CSS into CommonJS
'css-loader',
// Compiles Scss to CSS
base.module.rules[1].use[2],
]
},
{
test: /\.less$/i,
use: [
// Creates `style` nodes from JS strings
cssLoaderPlugin,
// Translates CSS into CommonJS
'css-loader',
// Compiles Less to CSS
'less-loader',
]
}
]
}
};
|
4.7. 目标七:用webpack引入图片 §
index.js
1
2
3
4
5
6
7
|
import x from './x.js'
const div = document.getElementById('app')
console.log('div')
console.log(div)
div.innerHTML = `
<img src="./assets/BlkHo.gif">
`
|
报错 Cannot set property 'innerHTML of null'
.innerHTNL前面的div是个null
- 未取到
div,console.log(div)
- 注意
<div id="app"></div>中的id没有#
src/assets/index.html
1
2
3
4
5
|
...
<body>
<div id="app"></div>
</body>
...
|
yarn start的页面中为请求到图片
- 因为
webpack-dev-server加载的路径并不是当前目录,而是dist目录
怎样加载图片路径
index.js
1
2
3
4
5
6
|
import x from './x.js'
import gif from './assets/BlkHo.gif'
const div = document.getElementById('app')
div.innerHTML = `
<img src="./assets/BlkHo.gif">
`
|
Error: Can't resolve 'file-loader'
- 手动安装
file-loader
yarn add file-loader --dev
webpack.config.base.js
1
2
3
4
5
6
7
|
...,
{
test: /\.(png|svg|je?pg|gif)$/i,
use: [
'file-loader',
],
},
|
index.js
1
2
3
4
5
6
7
8
9
10
11
12
|
import from './x.js'
import gif from './assets/BlkHo.gif'
import png from './assets/1.png'
console.log(gif)
console.log(png)
const div = document.getElementById('app')
console.log('div')
console.log(div)
div.innerHTML = `
<img src="${gif}">
<img src="${png}">
`
|
- 自动添加哈希
- 图片放到本地的
assets
- 使用
import得到路径的引用
- 将引用放到
src
file-loader的作用就是把文件变成文件路径
4.8. 目标八:用webpack的 import() 实现懒加载 资源异步加载 §
当模块数量过多、资源体积过大时,将暂时用不到的模块延迟加载
使得页面初次渲染时用户下载的资源尽可能小
后续的模块等到恰当的时机再去触发加载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
const button = document.createElement('button')
button.innerText = '懒加载'
button.onclick = () => {
console.log("点击了 button")
const lazyPromise = import('./lazy.js')
// 加载时异步的 拿到的是一个 Promise对象实例
lazyPromise.then((module) => {
console.log(module)
const fn = module.default
fn()
}, () => {
console.log("模块加载错误")
})
}
div.appendChild(button)
|
4.9. 目标九:部署到GitHub Pages §
本地打包
本地预览
上传代码
webpack 一键部署到 github
原来的部署过程
1.将“站点”部署 上传 dist 目录
2.使用git分支 上传到 gh-pages 分支
1
2
3
4
5
6
|
rm -f dist
git add . && git commit -am "remove dist" && git push
yarn build
git branch gh-pages
git checkout gh-pages
|
- 手滑把
.gitignore删除了,重置,撤回上一步
只保留 dist node_modules .gitignore
1
|
git add . && git commit -m "remove source code" && git push
|
拷出 dist 的所有内容
1
2
|
mv dist/* ./
rm -rf dist
|
上传网站根目录
1
|
git add . && git commit -m "remove create website" && git push --set-upstream origin gh-pages
|
一个分支用来写代码 一个分支用来预览
- loading 顺时针转 请求 逆时针转 下载
- git stash 将修改过的文件暂存
- git checkout master
- git stash pop
用脚本一键部署 deploy.sh
1
2
3
4
5
6
7
8
9
|
yarn build &&
git checkout gh-pages &&
rm -rf src *.sh *.js *.json yarn.lock *.css *.scss *.less *.styl *.gif *.png &&
mv dist/* ./ &&
rm -rf dist;
git add . &&
git commit -m "preview gh-pages" &&
git push
git checkout -
|
以后如果改了代码 需要更新预览,先提交master 在一键脚本
webpack 一键部署到 gitee
- 登录网站 新建仓库
- 点击SSH
- 在
git remote add origin git@gitee.com:xmasuhai/webpack-demo-1.git中修改origin为gitee
git remote add gitee git@gitee.com:xmasuhai/webpack-demo-1.git
git push -u gitee master
git remote -v查看仓库
再次新建一个脚本deploy_cn.sh
1
2
3
4
5
6
7
8
9
|
yarn build &&
git checkout gh-pages &&
rm -rf src *.sh *.js *.json yarn.lock *.css *.scss *.less *.styl *.gif *.png &&
mv dist/* ./ &&
rm -rf dist;
git add . &&
git commit -m "preview gh-pages" &&
git push gitee gh-pages:master &&
git checkout -
|
git github gitee gitlab
4.10. 目标十:自己写一个loader §
4.11. 目标十一:自己写一个plugin §
4.12. 目标十二:用webpack实现模块热替换HMR §
- 目标十二:用
webpack实现模块热替换HMR
- 目标十三:用
webpack引入TypeScript
- 目标十四:使用
Flow检查器
- 目标十五:用
webpack引入各大框架Vuw React Electron
- 目标十六:用
webpack实现 i118n
5. 从webpack看前端工具的历史 §
9. 死掉的前端工具 §
- Grunt 太慢,几死
- Gulp 速度ok 但没 webpack 繁荣
- Require.js 几死
- Sea.js 已死
- Browserify 已死
9. 和webpack竞争的工具 §
rollup
- 比 webpack 的打包体积更小
- 生态不丰富
- 适合库的开发
parcel
- 比 webpack 配置简单
- 公司要求负载的配置,变态的需求
- 适合demo学习
snowpack
9. 基于webpack的工具 §
@vue/cli
create-react-app
- 快速创建
react项目
- 基本不用配置
- 特殊配置看文档
@angular/cli
- 快速创建
angular项目
- 基本不用配置
- 特殊配置看文档
6. 总结 §
术语总结
自我驱动学习法
要点
7. 问答 §
问答1:要将webpack学到什么程度
问答2:面试问webpack怎么答
- 相关博客
- 几个手写
webpack config的项目
- 使用
@vue/cli、create-react-app
8. 学英语 §
- 调手机操作系统语言为英语
- 订阅
Hacker News、JS Daily
- 优先看英文文档
工具
参考文章
相关文章
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名
- 河
掘
思
知
简