每天对自己多问几个为什么,总是有着想象不到的收获。 一个菜鸟小白的成长之路(copyer)
为什么要搭建本地服务器?
在前面的学习过程中,每次当有代码变动的时候,就需要手动的去打包刷新,这样很很麻烦的。所以,需要自动编译
,当代码变化的时候,自动更新。刷新等。
webpack提供的几种方式用来自动编译
- webpack watch mode
- webpack-dev-server(常用)
- webpack-dev-middleware
webpack watch
webpack 提供了 watch模式
- 在该模式下,webpack依赖图的所有文件,只要有一个发生了更新,那么代码将被重新编译
- 就不需要手动去重新打包了
如何开启watch模式呢
- 方式一:在导出的配置中,添加
watch:true
- 方式二:在启动webpack的命令中,添加
--watch
的标识
代码如下:
//第一种方式: webpack.config.js
module.exports = {
entry: '',
output: '',
//开启实时监听,自动编译
watch: true
}
// 第二种方式: package.json
"scripts": {
"build": "webpack --watch"
},
缺点:
就是不会自动刷新浏览器,(当然可以借用liver server插件也可以进行自动刷新)
webpack-dev-server
特点:自动编译,自动刷新
安装:
npm install webpack-dev-server -D
使用:
//package.json
"scripts": {
"dev": "webpack server"
},
运行指令:
npm run dev //就会创建一个本地的服务器 express
webpack-dev-server的执行基本流程:
执行
npm run dev
, webpack-dev-server服务,也是间接的执行webpack-cli
就会进行打包,但是这里的打包有点不一样
这里打包只会把
打包后的资源放在内存里面
,然后提供给express的静态资源进行部署
,创建服务器,但是并没有对打包文件进行输出
(就是说dist文件夹下没有任何内容
)why?
这也就解释了,想要打包的时候。还是需要运行打包的运行指令(
npm run build
),来进行文件的输出
webpack-dev-server的配置
开发中 Server(devServer) | webpack 中文网 (webpackjs.com)
webpack.config.js也是可以对webpack-dev-server进行配置的
//webpack.config.js
module.exports ={
devServer: {
//配置信息
}
}
配置信息: contentBase
webpack -dev-server
只会对webpack的依赖图
中的文件进行处理,但是有些文件没有在依赖图里面,那么该如何做呢?
比如说:public文件夹中的favicon.ico
图标
在前面的学习中,是使用的插件CopyWebpackPlugin
来进行处理的,复制到打包文件里面去,然后使图标生效。
那如果不使用CopyWebpackPlugin
插件呢?
我们知道 favicon.icon
肯定没有在webpack的依赖图里面。webpack-dev-server
就提供一个属性,专门用来解决此类问题的
module.exports ={
devServer: {
contentBase: './public'
}
}
解释: 就是当文件没有在依赖图里面,想要加载的话,就从public
文件夹里面去找
使用场景
开发阶段: 使用contentBase
,因为打包之后,是没有public文件的
打包阶段: 使用CopyWebpackPlugin
认识模块的热替换(HMR
)
HMR
:全称是 Hot Module Replacement,模块热替换
模块热替换
是指在 应用程序运行过程中,替换,添加,删除模块
,而无需重新刷新整个页面
。
HMR 通过几种方式来提高开发速度
不重新加载整个页面
,这样可以保留某些应用程序的状态不丢失- 值更新需要变化的内容,节省开发的时间
- 修改了css,js源代码,会立即在浏览器更新,相当于直接在浏览器的devtools中直接修改样式
如何使用HMR呢
- 默认情况下,webpack-dev-server已经直接HMR,只需要打开就行
- 在不开启HMR的情况下,当我们修改了源代码之后,整个页面会自动刷新,使用的是
live reloading
代码演示
module.exports ={
devServer: {
hot: true
}
}
(HMR开启成功)效果图:
意味:等待更新从webpack-dev-server
测试代码:
// element.js
let el = document.createElement('div')
el.className = 'title'
el.innerHTML = 'copyer'
document.body.appendChild(el)
console.log('11111')
效果图1:
当我们修改element.js
打印为 console.log('22222')
效果图2:
是不是感觉有点问题。如果页面没有刷新的话,控制台
也应该是没有刷新的,所以打印的22222
应该HMR的下面,但是没有,就是直接替换了111111
,所以页面也是进行刷新了的。
之所以还是刷新页面,是因为还没有通知哪些模块的跟新是热替换
, 需要我们手动添加
import './js/element.js'
//指定element.js需要热跟新
if(module.hot) {
//第二个参数,加载成功的回调函数
module.hot.accept('./js/element.js', () => {} )
}
效果图3:
这里就没有刷新页面了。
框架的HMR
- 比如 vue 开发中, vue-loader 使 vue组件已经支持 HMR 了,不需要手动
module.hot.accept()
- 比如react开发中,react-refresh
devServer的其他属性
host
: 主机地址
port
: 端口号
open
: 是否打开浏览器。默认为false,true,就会打开浏览器
compress
:是否为静态文件开启gzip。 默认为false,true就会压缩
proxy的原理
DevServe本身也是一个服务器(experss),服务器 与 服务器之间访问是没有跨域的问题的。所以,远程的服务器
把数据返回给本地的服务器(express)
,再由本地的服务器返回数据给浏览器
实例:
远程的服务器:localhost: 3000/data是提供数据的
express地址: localhost:8080
远程服务器的地址: localhost: 3000
代码:
proxy: {
"/api": "http://localhost:3000"
}
axios.get('/api/data', () => {})
上面使用axios请求接口。
本地的服务器的地址: http://localhost:8080/api/data
那么就会映射到远程的服务器地址: http://localhost:3000/api/data
但是远程的服务器提供的地址是:http://localhost:3000/data
所以需要重写路径
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: {
"^/api": '' //正则匹配/api
}
}
}
secure属性解释
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: {
"^/api": '' //正则匹配/api
},
secure: false
}
}
该属性默认的情况下,是为true,就是针对于服务器是https
,访问https
是需要证书的,所以这样代理是不成功的。但是又没有证书,又想访问https
, 就需要把该属性设置为false
,就可以正常的代理了。
changeOrigin属性
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: {
"^/api": '' //正则匹配/api
},
secure: false,
changeOrigin: true
}
}
在源代码中,请求头的地址为: http://localhost:8080
,当我们设置这个属性(changeOrigin: true
)之后,传递给远程的服务器中的请求头的地址为http://localhost:3000
,验证请求源成功之后,就返回正确的数据。