webpack搭建本地服务器

对于webapck来说,搭建本地服务器的目的是为了能自动对打包后的文件进行展示,并且当文件改变时,能自动的重新打包并展示。

webpack 中提供了几个不同的选项,可以帮助你在代码发生变化时自动编译代码:

  • webpack's Watch Mode

  • webpack-dev-server(常用)。

  • webpack-dev-middleware

Using Watch Mode

就是在webpack打包命令后加入--watch配置:

1
npx webpack --watch

输入命令后我们发现,我们会发现他不会退出命令行,这是由于它正在监听文件的变化进行打包更新。

但它的缺点是,对于展示,每次都需要手动刷新浏览器才能看到更改。

Using webpack-dev-server

webpack-dev-server是一个基于webpack的静态文件服务器,它可以监听文件的变化,并自动刷新浏览器。

安装webpack-dev-server:

1
npm i webpack-dev-server -D

然后对devServer进行配置,对于其中的配置项,后面再说,先这样用着:

1
2
3
4
5
devServer: {
port: 8080,
open: true,
host: '0.0.0.0'
}

webpack-dev-server启动命令:

1
2
3
npx webpack serve
# 或
npx webpack-dev-server

接下里来我来介绍一些webpack-dev-server的常用配置项:

配置项 说明 默认值 示例
compress 是否启用gzip压缩,即由webpack开启的服务返回的资源会通过gzip压缩,由浏览器进行解压,可以提高传输效率,但只适用于开发环境,生产环境推荐使用nginx false
headers 为所有响应添加响应头,可以解决跨域问题,但只是用于开发环境 headers: {'Access-Control-Allow-Origin': '*'}
host 指定要使用的主机。即允许外部可以访问我们的主机,在此目的是外部可以查看我们的项目。 host: '0.0.0.0'(进行此设置我们的主机可以被任意外部访问)
hot 启用 webpack 的热模块替换功能 true
open 告诉 dev-server 在服务器启动后打开浏览器。将其设置为 true 以打开默认浏览器 false open: true
port 指定要侦听以下请求的端口号 8080 port: 8000

接下来单独介绍一些配置项,不适合再用上述表格了。

proxy

看一下官方的描述:

Proxying some URLs can be useful when you have a separate API backend development server and you want to send API requests on the same domain.

当您拥有单独的 API 后端开发服务器并且希望在同一域上发送 API 请求时,代理某些 URL 可能很有用。

proxy主要是用于解决跨域问题的,在项目开发中,前端开发和后端开发可能处于两个服务器,甚至于部署时也可能部署在不同的服务器上,而由于浏览器的同源策略,仅允许同源的请求访问,因此当我们访问后端的数据时,可能是获取不到的,这个时候,就可以通过配置proxy代理解决这个问题,但要注意,这个配置仅仅适于开发环境

proxy的配置内部其实是基于http-proxy-middleware库实现的,详细配置点击上述链接即可,我这里只介绍几个常用的配置。

  • context:可以填写字符串或数组,这意味着它可以匹配多种路径规则。

    • 注意:一定要是要有devServer启动的服务携带的路径请求才能被代理。
    • 比如当前服务为:http://localhost:8080,路径规则为/api,那么只有发送的请求一定要是http://localhost:8080/api才能被代理。
  • target:代理目标地址。

  • pathRewrite:重写路径,可以是一个对象也可以是一个函数。

  • changeOrigin:默认情况下,代理时会保留主机标头的来源,您可以将 changeOrigin 设置为 true 以覆盖此行为。其实就是修改中间代理服务器发送到后端服务器时请求头中的host标头,host默认是本机的ip和端口,设置changeOrigin: true,host就变为目标服务器的ip和端口。

    • host标头:host标头的出现是因为HTTP/1.1版本中由于虚拟技术的出现导致的单IP地址托管多个网站的问题。服务器可以根据host的值选择对应的网站配置。

给出一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
proxy: [
{
context: ['/api1', '/api'],
target: 'http://127.0.0.1:3000',
// pathRewrite:{
// '^/api1': '',
// '^/api': ''
// },
pathRewrite: (path) => {
if (path.startsWith('/api1')) {
return path.replace('/api1', '');
} else if (path.startsWith('/api')) {
return path.replace('/api', '');
}
},
},
];

上述代码中,我定义了两个代理,一个代理/api1,一个代理/api,我想要都将他们通过pathRewrite替换/api/api1为空,这个时候,一定要将/api1匹配规则写在前面,这是由于^/api匹配规则包含^/api1,会对其他操作造成影响。

对于proxy解决跨域的问题,其实就是利用了服务器之前不存在同源策略的问题,webpack通过webpack-dev-server开启一个同源中间服务器,浏览器发送请求到该同源服务器,由此服务器再将请求发送给后端服务器,最后再通过中间服务器返回给前端。

画个图表示:

historyApiFallback

historyApiFallback是为了解决单页面项目刷新后资源找不到(404)的情况,资源找不到的根本原因在于浏览器与服务器对路由处理的根本性差异。

举个例子:比如我们进行页面导航时,URL会发生对应的变化,这个时候我们进行刷新,会根据URL的文件路径去资源服务器的文件系统下查找对应的文件,如果找不到,就会返回404。而在页面中的URL改变,是由前端路由接管的,并不会去请求服务器,直白来讲,其实就是通过js监听URL改变,导入对应的从资源服务器下载的js文件,但本质上,在不刷新的情况下,无论URL怎么改变,当前页面始终都是在WEB服务器配置的默认返回的html文件,如index.html

注意:此配置仅适用于开发阶段,对于生产阶段,要单独在WEB服务器(nginx)中进行配置。

这里给出一幅图便于理解上述内容:

前面我们提到了,在单页面应用里,无论路由怎么变化,始终展示的都是在WEB服务器配置的默认返回页面,一般默认是index.html页面,当我们进行historyApiFallback: true时,所有404请求都会被重定向到index.html,无论请求路径是什么,对于重定向的操作,URL并不会改变,所以index.html中的js脚本会根据当前路由进行逻辑处理并渲染对应的组件。

一般进行如下配置即可:

1
2
3
devServer: {
historyApiFallback: true;
}

有时候我们可能希望部分路径重定向到其他页面,我们需要进行如下配置:

1
2
3
4
5
6
devServer: {
rewrites: [
{ from: /\/api\//, to: null }, // 不重定向API请求
{ from: /./, to: '/index.html' }, // 其他重定向
];
}

Using webpack-dev-middleware

webpack-dev-middleware是一个包装器,它将webpack处理的文件发送到服务器。

这意味着我们需要手动实现一个服务器,与webpack-dev-middleware一起使用。webpack-dev-server内部就使用了webpack-dev-middleware,它同时帮助我们开启了一个服务器,所以对于webpack-dev-server来说,我们只需填写一个服务器相关的配置即可。

示例:webpack-dev-middlewareexpress结合使用

安装webpack-dev-middlewareexpress

1
npm i -D express webpack-dev-middleware

我们同时需要在webpack配置文件中配置output.publicPath

1
2
3
4
output: {
// 这个配置会在express中被获取,作为静态资源的路径使用
publicPath: '/';
}

创建一个server.js文件,并写入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();
// 注意:如果配置文件是一个函数的话,需要调用一下,我们需要获取的是配置文件对象
// const config = require('./webpack.config.js')();
const config = require('./webpack.config.js');
const compiler = webpack(config);

// 告诉 Express 使用 webpack-dev-middleware并 使用 webpack.config.js 配置文件作为基础。
app.use(
webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
})
);

// Serve the files on port 3000.
app.listen(3000, function () {
console.log('Example app listening on port 3000!\n');
});

接下来只需要通过node server.js进行即可,通过这个操作,也是可以做到当文件改变时,能自动的重新打包并展示。