Vue3和TypeScript学习笔记coderwhyDay09之devServer


为什么搭建本地服务器?

之前写代码,每次更改都要npm run build编译相关代码很麻烦。
我们希望做到,当文件发生变化时,可以自动完成编译和展示。(备注:live-server插件可以自动编译展示)

自动完成编译,webpack提供以下方式
webpack watch mode
webpack-dev-serve(常用)
webpack-dev-middleware


Webpack watch

package.json中配置

 "scripts": {
    "build": "webpack --watch"
  }

在webpack.config.js中配置

watch:true

webpack-dev-serve

上面两种方式的配置都可以监听文件变化,但本身没有自动刷新浏览器功能,开发中不常使用
目前,我们可以在VSCode中通过live serve插件完成浏览器自动挡刷新功能。
如果我们希望在不使用live-serve时,仍具备live reloading(实时重加载),安装webpack-dev-serve

1.安装webpack-dev-serve
npm install webpack-dev-serve -D
package.json

 "scripts": {
    "build": "webpack",
    "serve": "webpack serve"
  }

npm run serve就可以实时重载浏览器页面了。

注意:
serve通过webpack-cli来帮助我们做解析的
webpack-dev-serve在编译之后不会写入到任何输出文件,而是将bundle文件保留在内存中。webpack-dev-serve使用了一个memfs库。

2.配置文件

开发阶段:contentBase
打包阶段:CopyWebpackPlugin
我们在开发阶段,如果每次都对资源进行copy,比如资源有很多视频,这样很耗费性能。
所以,开发阶段,我们常采用contentBase来告诉devServer从什么位置找文件。
如果资源没有从webpack加载到,会从contentBase配置的路径进行加载。
等到打包阶段时,使用CopyWebpackPlugin

devServer: {
    contentBase: "./public"
}

模块热替换

什么是HMR?
Hot Module Replacement模块热替换
指在应用程序运行过程中,替换、添加、删除模块,而无需重新刷新整个页面

HMR通过以下几种方式来提高开发速度
不重新加载整个页面,这样可以保留某些应用程序的状态不丢失
只更新需要变化的内容,节省开发时间
修改了css、js源码,会立即在浏览器更新

如何使用HMR?
默认情况下,webpack-dev-serve已支持HMR,我们只需开启即可。
在不开启HMR的情况下,当我们修改了源码后,整个页面会重新刷新,使用的是live reloading

devServe:{
	hot:true
}

框架的HMR
在开发Vue、React项目,我们修改了组件,希望进行热更新,应该如何操作呢?
vue开发中,我们使用vue-loader
react开发中,有react-refresh


HMR原理

我们先要明白http连接和socket连接有什么区别。
TCP、HTTP、Socket
Socket常用在即时通信,比如微信、直播聊天、送礼物、直播进场等场景

http连接
客户端发送http请求—>和服务器建立连接—>服务器做出响应—>断开连接
HTTP是短连接,Socket(基于TCP协议的)是长连接。尽管HTTP1.1开始支持持久连接,但仍无法保证始终连接。而Socket连接一旦建立TCP三次握手,除非一方主动断开,否则连接状态一直保持。

HTTP连接服务端无法主动发消息,Socket连接双方请求的发送先后限制。这点就比较重要了,因为它将决定二者分别适合应用在什么场景下。HTTP采用“请求-响应”机制,在客户端还没发送消息给服务端前,服务端无法推送消息给客户端。必须满足客户端发送消息在前,服务端回复在后。Socket连接双方类似peer2peer的关系,一方随时可以向另一方喊话。

HMR的原理是什么呢?如何做到只更新一个模块中的内容呢?
在这里插入图片描述

webpack-dev-server会创建两个服务:提供静态资源的服务(express)Socket服务(net.Socket)
express server负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)
HMR Socket Server是一个socket长连接。
长连接有个好处是建立连接后双方可以通信(服务器可以直接发送文件到服务端)。
当服务器监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js(update chunk)
通过长连接,可以直接将这两个文件主动发送给客户端(浏览器)。
浏览器拿到这两个新文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新


host配置

host设置主机地址:默认localhost(localhost本质是域名,被解析成127.0.0.1)。
如果希望其他地方也能访问,设置为0.0.0.0

127.0.0.1
回环地址:主机发出去的包,直接被自己接收。
正常的数据库包 应用层—传输层—网络层—数据链路层—物理层。而回环地址,是在网络层直接就被获取到了,是不会经过数据链路层和物理层的。比如我们监听127.0.0.1时,在同一网段下的主机中,通过ip地址是不能访问的。

0.0.0.0,在同一个网段下的主机中,通过ip地址是可以访问的

port 设置监听端口,默认8080
open是否打开浏览器:默认false不打开
compress是否为静态文件开启gzip 压缩:默认false


解决跨域:
1.当前静态资源和api服务器部署到一块(Tomact、Express、Koa ),这样,访问不会有跨域问题
2.让服务器把跨域关掉,但不安全
3.nginx代理

解决跨域都需要前端和后端配合,开发阶段一般配置devServe里的代理(proxy在开发阶段配置),部署阶段后端配置
proxy官网教程

Proxy

在这里插入图片描述
在这里插入图片描述
proxy目的是设置代理来解决跨域访问的问题
比如我们一个api请求是http://localhost:8888,但本地启动服务器的域名是http://localhost:8000,这个时候发送网络请求就会出现跨域的问题
那么我们可以将请求先发送一个代理服务器,代理服务器和API服务器没有跨域的问题,就可以解决我们的跨域问题了。

进行如下设置:
target:代理到的目标地址。
 比如/api-hy/moment会被代理到http://localhost:8888/api-hy/moment
pathRewrite:默认情况下,我们的/api-hy也会被写入到url中,如果希望删除,可以使用pathRewrite
secure:默认true,默认情况下不接收转发到https的服务器上
changeOrigin:表示是否更新代理后请求的headers和host地址


resolve模块解析

resolve用于设置模块如何被解析
可以帮助webpack从每个require/import语句中,找到需要引入的合适的代码模块

webpack能解析三种文件路径
绝对路径
	由于已经获得文件的绝对路径,因此不需再进一步解析
相对路径
	在这种情况下,使用import或require的资源文件所处的目录,被认为是上下文目录
	在import/require中给定的相对路径,会拼接此上下文路径,来生成模块的绝对路径
模块路径
	在resolve.modules中指定的所有目录检索模块
	默认值['node_modules'],所以默认会从node_modules中查找文件

如何确定我们导入的模块是文件还是文件夹(库)呢?
如果文件有扩展名,则直接打包文件。
否则,将使用resolve.extensions选项作为文件扩展名解析

 resolve: {
    extensions: [".js", ".json", ".mjs", ".vue", ".ts", ".jsx", ".tsx"]
 }

如果是文件夹
根据resolve.mainFiles配置选项中指定的文件顺序进行查找
resolve.mainFiles的默认值是[‘index’],再根据resolve.extensions来解析扩展名


extensions和alias配置
extensions:解析到文件时自动加扩展名
alias:给常见路径起别名


开发和生成环境配置

当我们打包的时候,如果还是使用webpack.config.js配置文件,不是很合理。配置中有些在开发中,有些在生成中使用。
所以,要讲开发环境和生成环境配置分离。

1.我们创建3个文件
webpack.comm.config.js:共同配置
webpack.dev.config.js:开发阶段配置
webpack.prod.config.js:生成阶段配置

2.将comm合并到dev、prod中。
npm install webpack-merge -D
通过merge函数将comm配置分别合并到dev、prod中

"scripts": {
    "build": "webpack --config ./config/webpack.prod.config.js",
    "serve": "webpack serve --config ./config/webpack.dev.config.js"
  }

在这里插入图片描述
这样,我们在执行npm run build 打包生成阶段。 npm run serve打包开发阶段


webpack.comm.config.js

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { DefinePlugin } = require("webpack");
const { VueLoaderPlugin } = require('vue-loader/dist/index');

module.exports = {
  target: "web",
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, "../build"),
    filename: "js/bundle.js",
  },
  resolve: {
    extensions: [".js", ".json", ".mjs", ".vue", ".ts", ".jsx", ".tsx"],
    alias: {
      "@": path.resolve(__dirname, "../src"),
      "js": path.resolve(__dirname, "../src/js")
    }
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader", "postcss-loader"],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
      // },
      {
        test: /\.(jpe?g|png|gif|svg)$/,
        type: "asset",
        generator: {
          filename: "img/[name]_[hash:6][ext]",
        },
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024,
          },
        },
      },
      {
        test: /\.(eot|ttf|woff2?)$/,
        type: "asset/resource",
        generator: {
          filename: "font/[name]_[hash:6][ext]",
        },
      },
      {
        test: /\.js$/,
        loader: "babel-loader"
      },
      {
        test: /\.vue$/,
        loader: "vue-loader"
      }
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
      title: "哈哈哈哈"
    }),
    new DefinePlugin({
      BASE_URL: "'./'",
      __VUE_OPTIONS_API__: true,
      __VUE_PROD_DEVTOOLS__: false
    }),
    new VueLoaderPlugin()
  ],
};


webpack.dev.config.js

const { merge } = require('webpack-merge');

const commonConfig = require('./webpack.comm.config');

module.exports = merge(commonConfig, {
  mode: "development",
  devtool: "source-map",
  devServer: {
    contentBase: "./public",
    hot: true,
    // host: "0.0.0.0",
    port: 7777,
    open: true,
    // compress: true,
    proxy: {
      "/api": {
        target: "http://localhost:8888",
        pathRewrite: {
          "^/api": ""
        },
        secure: false,
        changeOrigin: true
      }
    }
  },
})


webpack.prod.config.js

const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyWebpackPlugin = require('copy-webpack-plugin');
const {merge} = require('webpack-merge');

const commonConfig = require('./webpack.comm.config');

module.exports = merge(commonConfig, {
  mode: "production",
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: "./public",
          globOptions: {
            ignore: [
              "**/index.html"
            ]
          }
        }
      ]
    }),
  ]
})


  • 以上仅是简单入门了解,更多内容看官网配置
    babel官网文档
  • 以上笔记参考coderwhy老师的Vue3和TypeScript。
    老师讲课链接:课程链接
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值