webpack4 学习 --- webpack和webpack-dev-server

时间:2022-01-13 15:36:17

  直入主题吧,建个文件夹webpack-tut并进入,打开cmd命令窗口,执行npm init -y 命令,创建package.json 文件,转化为了node 项目,这样好管理依赖和版本什么的。此时可以学习webpack了。首先要安装webpack,不过这里要注意,webpack4 把webpack 命令单独抽了出来,形成了一个单独的包webpack-cli ,我们安装webpack的同时要把它安装上

npm install webpack webpack-cli --save-dev

  webpack命令,就是我们在命令窗口中写的命令,我们在cmd 命令窗口中,输入webpack,  就会把打包,webpack 就是一个命令。为什么要单独形成一个包呢?因为webpack-cli 还提供了两个其它的功能,init 和 migrate命令,使我们快速创建webpack 配置和提供升级迁移。不过这两个基本不用,了解一下就可以了。我们只要记住安装webpack的同时安装上webpack-cli就可以了。

  webpack 是模块打包工具,那就建几个文件让它打包,在webpack-tut 文件夹中新建一个src 文件夹,存放我们的源文件,再在src 文件夹中新建index.js 文件和component.js 文件,component.js 文件

export default (text = 'hello world') => {
const element = document.createElement('div');
element.innerHTML = text; return element;
}

index.js 文件

import component from './component';
document.body.appendChild(component());

  怎么打包呢?在webpack4 下,直接执行webpack 命令。在package.json的scripts的字段中,写上 “build”: “webpack”,  执行npm run build 命令,生成了dist 目录,表示打包成功了,但也发现了一个WARNING

webpack4 学习 --- webpack和webpack-dev-server

  Webpack4 提供了一个mode 配置项 ,它有两个选择: production 和 development, 就是生产模式和开发模式,不同模式,配置肯定不一样。mode 可以在命令行进行配置,   build 命令改成 webpack --mode production  或 webpack --mode development,就配置成功了。

  以上就是webpack4 提供的零配置。简单总结一下,当执行webpack命令,而又没有配置文件时,webpack会寻找默认的入口文件。默认的入口文件就是项目根目录下的src目录下的index.js文件,这也是新建src 目录和把js文件命名为index.js 的原因。打包后文件,它也定义了默认的输出路径,打包后的文件放到dist 目录中, 文件名为main.js 文件, 同时,它还会根据你指定的mode 进行打包优化。

  对于小型的项目,零配置没有问题,但对于大型的web 项目,它不光有js, 还有css, image 等,零配置就无能为力,还是要退回写webpack的配置文件。在webpack-tut中新建webpack.config.js 文件(配置文件的默认名称),配置文件和以前相同,都是entry, output, module, plugins选项。 零配置的时候,webpack 给我们提供了entry 和output, 如果觉得ok的话,可以使用,那配置文件中,只写module 和plugins 就可以,如果觉得不ok 的话,可以写entry 和output, 把它覆盖掉,这都没有问题, mode 的配置也是如此,可以在命令行中指定,也可以在配置文件中书写,现在用配置文件的方式,把零配置实现一下

const path = require('path');

module.exports = {
mode: 'development',
entry: path.join(__dirname, 'src/index.js'),
output: {
path: path.join(__dirname, 'dist'),
filename: 'main.js'
}
}

  npm run build 也打包成功了,最后验证一下,在根目录下建一个html 文件,script 引入 dist/main.js, 没有问题。但这时你也会发现一个问题,改动js文件后,都要执行npm run build 命令,同时要手动刷新浏览器才能看效果,非常麻烦,不利于开发,怎么办? 使用webpack-dev-server, 自动打包,自动刷新

  webpack-dev-server 是 webpack自带的一个小型服务器,它会检测每个文件的变动,每当有文件改动时,它就会重新打包,然后浏览器会自动刷新页面,这样就可以时时看到代码的变动,大大开发了开发效率。这也是所谓的liveload 或hotload(热更新)。但这里要注意,webpack-dev-server 打包后文件是放到内存中的,而不像npm run build 把文件打包到硬盘上,默认情况下,webpack会把打包生成的文件生成到根目录下,就相当于在根目下多了打包后的文件,可以通过开发者工具的source 面板来查看一下。

首先 npm install webpack-dev-server --save-dev 安装它,然后在scripts中,"dev": "webpack-dev-server",

webpack4 学习 --- webpack和webpack-dev-server

  npm run dev 启动服务器,但当我们更改代码,页面刷新但内容并没有进行改变,这是因为index.html 里面访问的js 文件是 dist 文件夹中的main.js, 而不是webpack 打包后生成的文件。把dist 文件夹删除,页面直接报错了,找不到main.js 文件,上面已经说了,webpack-dev-server 会把文件打包到项目根目录下,所以index.html 文件中应该引入当前文件夹下面的main.js。

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

  npm run dev 和npm run build 命令下,index.html 引入的js 文件路不一致,可以使用html-webpack-plugin 插件解决。npm install html-webpack-plugin --save-dev 安装,

插件的使用方式也简单,配置文件中有一个plugins 属性,它是一个数组,每一个用到的插件都是数组中的一项。具体到每一个插件呢?插件都会暴露出构造函数,通过new 调用,就可以使用,如果插件还有配置项,它就给构造函数传递参数,只传一个对象作为参数

const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin'); // 引入插件 module.exports = {
mode: 'development',
entry: path.join(__dirname, 'src/index.js'),
output: {
path: path.join(__dirname, 'dist'),
filename: 'main.js'
},
plugins: [
new htmlWebpackPlugin({ // 插件的使用: new 调用构造函数,配置项就是构造函数的参数(对象形式的参数)
template: 'index.html'
})
]
}

  这时npm run dev 和npm run build都没有问题。这时我想对webpack-dev-server 进行配置,比如把端口改为9000, 配置文件提供了一个devServer 配置项,这个配置项和entry, output,module并列。devServer的配置是很庞大人,这里只是学几个简单实用的配置

module.exports = {
devServer: {
port: 9000, // 设置端口号
stats: 'errors-only', // 只有产生错误的时候,才显示错误信息,日志的输出等级是error.
overlay: true // 当有编译错误的时候,在浏览器页面上显示。
},
plugins: [
new htmlWebpackPlugin()
]
}

  重启服务器,这时看到项目启动在9000端口下。

webpack4 学习 --- webpack和webpack-dev-server

  这时你也应该发现了一个问题,就是当我们修改配置文件的时候,我们都要重新启动服务器,这有点麻烦,是不是可以监听配置文件的变化,自动重启服务器,这就要用到nodemon, nodemon 就是监听文件变化,重启服务器的。先安装nodemon, npm install nodemon --save-dev, 然后把 dev 命令改为下面

"dev": "nodemon --watch webpack.config.js --exec \"webpack-dev-server \""

  命令的意思是 监听webpack.config.js 的变化,然后执行(exec) webpack-dev-server 命令,注意\'' 双引号的转义。

  webpack-dev-server  还有两个配置项需要注意一下:

  contentBase: webpack-dev-server 会把所有的静态文件(css, js, img 等)进行打包,放到服务器根目录下,供我们访问。但我们可以访问服务器中的任何资源,一旦这些资源不是由webpack-dev-server 打包生成的,我们就要指定这些非打包生成的静态资源,比如index.html 文件,的位置,也就是contentbase,否则就会显示404. 如果不使用webpack-html-plugin, webpack 是不会打包生成index.html的, 那我们就要手动创建index.html, 这时index.html 文件,就是非webpack-dev-server 打包生成的资源,我们就要指定它的位置。因为我们在浏览器中输入localhost:8080, 我们是向webpack-dev-server 请求index.html 资源,webpack-dev-server 并没有生成这个文件,所以就会报错,如果告诉webpack-dev-server, index.html 在什么地方,它就会去找,就不会报错了。这就是contentbase的作用,webpack-dev-server 会向contentbase 指定的目录去找它没有打包生成的文件,你可能说,我们手动创建index.html时,也没有指定contnetbase, 整个项目也没有问题,这是因为contentbase的默认值是项目根目录,而我们创建的index.html 恰巧也在项目根目录下,所以没有问题。如果我们在项目根目录下新建一个文件夹叫public, 然后把index.html 放到里面,你再运行webapck-dev-serve , 它就会报错,这时就要指定contentbase, 它的取值就很清楚了,index.html(非webpack-dev-server 打包的资源)所在的位置, 绝对路径和相对路径都可以, 相对路径"build", 它是相对于项目根目录的, 绝对路径,path.join(__dirname, ‘public’)

  proxy: 代理,做过前后端联调,都知道代理的作用。当我们在本地开发的时候,访问的服务器是localhost. 但是后端的代码却在同事的电脑上,我们要访问同事的服务,就要设置代理了,要不然访问的永远都是本地的服务localhost,一个接口都没有。我们在请求的接口面前加一个标识,如axios.post(‘/api/login’), /api 就是标识,然后我们再在proxy 配置项里面给这个标识配置一个代理到的真实路径,如 ‘/api’ : ‘http://102.03.34.58/api’, 那么当我们调用接口的时候,实际上变成了http://102.03.34.58/api/login, 代理配置中的真实路径,就是会替换到请求中的标示

module.exports = {
devServer: {
contentBase:'build',
proxy: {
'/api': 'http://102.03.34.58/api'
},
port: , // 设置端口号
stats: 'errors-only', // 只有产生错误的时候,才显示错误信息,日志的输出等级是error.
overlay: true // 当有编译错误的时候,在浏览器页面上显示。
},
plugins: [
new htmlWebpackPlugin()
]
}    

  但有时候,可能是多个同事进行开发,接口没有那么规范,可能有的以api 开始,有的没有api, 根本就没有统一的标识,以上这种配置方式肯定不行, '/api' 标识还可以是一个对象

proxy: {
'/api': {
target: 'http://102.03.34.58',
pathRewrite: { '^/api': '' }
}
}

  这里要注意target 是请求的服务器地址,后面没有api, 使用这种方式配置以后,代理会在前端请求中的/api前面加上target, 相当于还是请求了 http://102.03.34.58/api/login,所以这里增加了pathRewrite 路径重写,所有以/api 开头的路径都转化为 空,所以最后真实的请求路径中 http://102.03.34.58/login. pathRewrite 中的属性是正则表达式,^以什么开始, 值 呢?就是匹配到的路径重写成会什么。

  proxy 中的属性'/api', 是前端发送请求时,请求接口中的url要加的参数,当真正发送请求时,webpack 服务中配置的代理碰到api 就会拦截,然后把它变成我们配置的真实的路径