WebPack
webpack is a module bundler
,那什么是module
呢?
在ES6之前,前端使用RequireJS或SeaJS实现模块化,RequireJS是基于AMD规范的模块化类库,而SeaJS则是基于CMD规范的模块化库,两者都是为了推广前端模块化的工具。
当ES6出现之后,由于ES6自带模块化,也是JS第一次支持module
。不过,很久以后,我们就可以直接使用import
和export
在浏览器和服务端导入和导出各个模块。为什么要很久以后呢?目前现代浏览器对模块支持程度不同,通用的做法是使用BabelJS或者Traceur将ES6代码转化为兼容ES5版本的JS代码。
ES6模块化的规范
- 一个模块一个JS文件
- 每个模块仅加载一次,每个JS也只执行一次,后续加载皆从内存中读取,也就是一个模块类似一个单例对象。
- 模块内声明的变量都是局部变量,不会污染全局变量。
- 模块内部变量或函数通过
export
导出为对象 - 模块间使用
import
相互导入
常见模块化的规范及解决方案
- JS的ES
- AMD规范的RequireJS
- CMD规范的SeaJS
- CommonJS规范的Node.js,Webpack同样遵循CommonJS的标准规范。
...
前端构建工具Webpack中的模块,Webpack中所有类型的文件都是模块(万物皆模块),包括JS、CSS、图片、字体、JSON...
例如:JS中使用import
或require
一张图片是会报错的,但在webpack下这是允许的,这归功于加载器loader
。通过加载器,webpack将JS的模块化推广到其他类型文件。这正是webpack与众不同的一面。
File-Loader
需求:单页中有一张图片,首次点击图片会旋转,再次点击则恢复原来的位置。
步骤:环境检查 环境搭建 业务编码
环境搭建
0. 环境检查
$ node -v
v8.1.2
$ npm -v
5.3.0
# 更新npm到最新版
$ npm i npm@latest -g
$ webpack -v
4.12.0
1. 项目初始化
$ mkdir demo && cd demo
$ npm init -y
2. 新建文件
$ vim index.js
$ vim index.html
demo
3. 安装react和react-dom
$ npm i react react-dom -D
$ vim index.js
import React from 'react'
import ReactDOM from 'react-dom'
Chrome出现错误
# 尚未捕获的语法错误:意外的标识符
Uncaught SyntaxError: Unexpected identifier
原因:
浏览器不支持 ES6 语法,而 import
语法就是其中之一。解决这个问题,可以找一些目前使用的替代方案,比如使用 Babel-cli 插件,将 ES6 转换成 ES5,然后再使用。当然你也可以不使用import
语法,而使用具有相同功能的 require
语法(非 ES6 语法)。
扩展:
ES6之前已经出现了JS模块加载的方案,最主要的是CommonJS和AMD规范。CommonJS主要应用于服务器,实现同步加载,如Node.js。AMD规范应用于浏览器,如Require.js,为异步加载。同时还有CMD规范,为同步加载方案如SeaJS。
ES6在语言规格的层面上,实现了模块功能,而且实现得相当简单,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。
ES6模块主要有两个功能:export
和 import
export
用于对外输出本模块(一个文件可以理解为一个模块)变量的接口import
用于在一个模块中加载另一个含有export接口的模块。
也就是说使用export
命令定义了模块的对外接口以后,其他JS文件就可以通过import
命令加载这个模块(文件)。
3. 安装webpack构建工具
# 安装webpack
$ npm i webpack -D
# 打包
$ npx webpack index.js -o bundle.js
# 提示是否安装webpack-cli,因为webpack4中将脚手架迁移到webpack-cli包中。
The CLI moved into a separate package: webpack-cli
Would you like to install webpack-cli? (That will run npm install -D webpack-cli) (yes/NO)
重新安装
$ npm i webpack webpack-cli -D
$ npx webpack index.js -o bundle.js
# webpack4引入了模式(mode),包括development、production、none,默认为production。
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/
再次打包
# 自定义打包
$ webpack index.js -o bundle.js --mode development
默认打包
$ npx webpack --mode development
# webpack4约定不指定输入文件则默认为src/index.js,输出为dist/main.js。
ERROR in Entry module not found: Error: Can't resolve './src' in 'D:\demo'
4. 调整结构
代码部署时除了需要要拷贝dist
目录外,还要拷贝index.html
,很麻烦,从部署上说仅需拷贝一个目录是最方便的,因此将index.html
移入dist
目录。
$ mkdir src
$ mv index.js src
$ mv index.html dist
$ rm -rf bundle.js
$ webpack --mode development
5. 实时刷新
问题:
入口文件src/index.js
修改后,如何通知给webpack重新构建dist/main.js
文件呢?
方案:
使用 watch
选项让webpack监控文件变化,一旦文件变化立即重构。但默认情况下,watch
是被禁用的。
# 启动watch
$ webpack --mode development --watch
npm允许在package.json
中使用scripts
字段自定义脚本命令
# npm自定义脚本
$ vim package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev":"webpack --mode development",
"watch":"webpack --mode development --watch",
"build":"webpack --mode production"
}
# 使用npm run执行自定义脚本
$ npm run watch
6. 浏览器自动刷新
webpack 提供 webpack-dev-server
,它是基于Node.js的Express框架的开发web服务器,提供实时刷新浏览器页面的功能。
# 更新npm
$ npm i npm@latest -g
# 安装webpack-dev-server
$ npm i webpack--dev-server -D
$ webpack-dev-server
'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序或批处理文件。
# npm v5.2.0引入的一条命令npx,目的是为了提升开发者使用包内提供的命令行工具的体验。
$ npx webpack-dev-server
# 开启监监控并指定基础内容目录
$ npx webpack-dev-server --mode development --content-base ./dist
业务编码
$ vim ./src/index.js
import React from 'react'
import ReactDOM from 'react-dom`
ReactDOM.render(hello, document.body)
# 错误
ERROR in ./src/index.js 5:16
Module parse failed: Unexpected token (5:16)
You may need an appropriate loader to handle this file type.
| import ReactDOM from 'react-dom'
|
> ReactDOM.render(hello, document.body);
@ multi (webpack)-dev-server/client?http://localhost:8080 ./src
# 使用了JSX语法webpack无法识别,使用babel-loader翻译。
$ npm i babel-loader -D
-- todo 未完待续
图片加载器
$ cd src
$ mkdir img
$ cp D:\logo\logo.png ./img/logo.png
$ vim src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import Logo from './img/logo.png'
$ npx webpack-dev-server --mode development --content-base ./dist
# 错误
ERROR in ./src/index.js
Module not found: Error: Can't resolve './img/logo.png' in 'D:\demo\src'
错误原因:需要文件加载器。
# 安装文件加载器
$ npm i -D file-loader
# 创建webpack配置文件
$ vim webpack.config.js
# 加载Node.js的path模块
const path = require('path')
# 模块对外暴露接口
module.exports = {
mode:'development',
devServer:{
contentBase:path.resolve(__dirname, 'dist')
},
module:{
rules:[
test:/\.(png|jpg|jpeg|gif)$/,
use:[
{loader:'file-loader', options:{}}
]
]
}
}
$ npx webpack-dev-server