webpack搭建本地服务器(六)
26 搭建本地服务器
1. 为什么要搭建本地服务器?

我们希望当文件变化,自动帮我们打包,并且显示到页面上。
2. Webpack watch

其实webpacl --watch是会被webpack-cli自动处理,变成watch:true
package.json
"scripts": {
"build": "webpack ---watch "
},
webpack-cli会帮助处理这个watch这个选项,把这个watch配置改成true
或者直接在webpack.config.js 里面添加watch:ture
const {VueLoaderPlugin } = require("vue-loader/dist/index");
module.exports = {
//设置模式
//development 开发阶段,会设置development
//production 准备打包上线的时候,设置production
mode:"development",
devtool:"source-map",
watch:ture,
以上配置完成后,运行npm run build,然后会打包。接下来在改变js里面的内容,一旦保存,就会自动打包。但是index.html必须重新刷新之后才能显示重新打包后的内容。
3. Webpack-dev-server的使用

//步骤一: npm install webpack-dev-server -d
//步骤二:安装之后,在package.json里面写入serve
"scripts": {
"build": "webpack",
"serve":"webpack serve"
},
//npm run serve实质上也是利用webpackcli帮助我们启动了一个本地服务器
//并且使用serve的时候,不需要专门设置watch为ture,因为dev-serve本身会给我们监听文件的变化。然后会对当前文件做编译,进行打包
//其实dev-serve是基于express框架搭建的本地服务器,这个服务器里面,有打包好的静态资源,返回给浏览器
但其实,这个使用并没有输出打包好的文件。也就是启动npm run serve 并没有产生build文件夹。其实webpack cli是有对源代码进行打包的,但是打包之后的代码没有做输出,而是放到了内存里面。目标是提高开发效率,如果是express从build文件夹里面读取文件的话,需要读取,转化成字节流,但是如果从内存读取的话,就是直接处理字节流。
4.配置devServer
4.1 配置static
可以在webpack.config.js文件中配置devServer
module.exports = {
//...
devServer: {
static: '/abc',
},
};
npm run serve之后
显示
<i> [webpack-dev-server] Content not from webpack is served from './abc' directory
如果webpack的静态资源中没有这个文件,将从index.html同级的abc文件夹中去加载。
如果没有copywebpackplugin这个插件设置的话,这时候既可以吧static改成"./public"。static里面这个文件夹,也会被打包。开发阶段使用contentBase,打包的时候使用copywebpackplugin
new CopyWebpackPlugin({
patterns:[
{
from:"public",
globOptions:{
ignore:[
"**/index.html"
]
}
}
]
}),
4.2. 配置HMR
一.什么是模块热替换

11111我们不希望浏览器随随便便刷新。在webpack里面,一个文件可以看出一个模块,使用热更新的时候,只有被更改或者替换,删除的模块才会被重新加载,其他的模块的状态是不会改变的。
二.设置模块热替换
a.对指定模块进行热替换。
module.exports = {
//...
target:"web"
devServer: {
static: '/abc',
hot:true
},
};
//一般情况下,设置 hot为ture的时候,我们会再设置一个target属性,这两个得同时打开
这时候再element.js里面的console.log('aaa')改成bbb,发现并没有热替换,而是全部都重新刷新了,这是因为devserver并不知刀要热更新哪个模块,所以所有模块都重新加载了。这时候我们需要修改文件的引入方式,

以前在main.js里面是这么引入的import "./js/elment.js",现在需要这么引入
import "./js/element.js"//第一次加载需要
if(module.hot){
module.hot.accept("./js/element.js", () => {
console.log('element.js文件被更改');
})
这样就可以进行热替换了。第一次运行npm run serve
[HMR] Waiting for update signal from WDS...
element.js:1 i am element.js file
element.js:26 ccc
main.js:40 50
main.js:41 ¥99.88
main.js:44 abc
main.js:44 cba
main.js:44 nba
main.js:45 123
index.js:551 [webpack-dev-server] Hot Module Replacement enabled.
index.js:551 [webpack-dev-server] Live Reloading enabled.
更改element.js里面的ccc
[HMR] Waiting for update signal from WDS...
element.js:1 i am element.js file
element.js:26 ccc
main.js:40 50
main.js:41 ¥99.88
main.js:44 abc
main.js:44 cba
main.js:44 nba
main.js:45 123
index.js:551 [webpack-dev-server] Hot Module Replacement enabled.
index.js:551 [webpack-dev-server] Live Reloading enabled.
The deferred DOM Node could not be resolved to a valid node.
index.js:551 [webpack-dev-server] App updated. Recompiling...
index.js:551 [webpack-dev-server] App hot update...
log.js:24 [HMR] Checking for updates on the server...
element.js:1 i am element.js file
element.js:26 ddd
main.js:34 element.js文件被更改
log.js:24 [HMR] Updated modules:
log.js:24 [HMR] - ./src/js/element.js
log.js:24 [HMR] App is up to date.
16, 17, 18行就重新被打印出来了,其他模块没有变化。
b.对全部模块进行热替换。

对于vue框架里面的文件处理来说,我们有vue-loader,来帮我们处理.vue文件。vue-loader在帮我们处理这个文件的过程中,已经帮我们设置出了加载这些文件时候的 module.hot.accept()等等的js代码了。
c.HMR的原理


4.3 配置hotOnly等


本来是浏览器请求bundle.js,服务器返回bundle.js但是如果文件过大的话,就是效率比较慢,这时候最好压缩。直接返回bundle.gzip,浏览器发现文件时gzip格式,就会自动给文件解压,。index.html默认不会压缩.
module.export = {
devServer:{
static:'./abc',
hot:true,
host:"localhost",
port:8080,
open:true,
compress:true
},
}
4.4 配置Proxy

跨域就是在当前的域名下面,去发送其他的http 请求,这个就是跨域。(概念:只要协议、域名、端口有任何一个不同,都被当作是不同的域。)

4.5 配置historyApiFallback

4.6 配置resolve

a.确认是文件还是文件夹

b.extensions和alias的配置

27 webpack开发和生产环境分离
一下的config的话,运行nom run build的话,就会按照config的配置去打包,但是这是我们开发的时候的配置,比如mode和devtool,还有插件cleanwebpackpluin

const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { DefinePlugin } = require("webpack");
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader/dist/index');
module.exports = {
target: "web",
mode: "development",
devtool: "source-map",
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "./build"),
filename: "js/bundle.js",
},
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
}
}
},
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 CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./public/index.html",
title: "哈哈哈哈"
}),
new DefinePlugin({
BASE_URL: "'./'",
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false
}),
// new CopyWebpackPlugin({
// patterns: [
// {
// from: "public",
// to: "./",
// globOptions: {
// ignore: [
// "**/index.html"
// ]
// }
// }
// ]
// }),
new VueLoaderPlugin()
],
};
我们想分离这个配置文件,在目录底下新建一个config文件夹,里面创建三个文件
1.webpack.comm.config.js
2.webpack.dev.config.js
3.webpack.prod.config.js
然后修改package.json文件
"scripts": {
"build": "webpack --config ./config/webpack.prod.config.js",
"serve": "webpack serve --config ./config/webpack.dev.config.js"
},
npm i webpack-merge -d
a.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()
],
};
b.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
}
}
},
})
c. 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"
]
}
}
]
}),
]
})
