目前开发的代码,为了运行需要有两个操作:
这个过程经常操作会影响的开发效率,希望可以做到,当文件发生变化时,可以自动的完成 编译 和 展示;
为了完成自动编译,webpack提供了几种可选的方式:
上面的方式可以监听到文件的变化,但是事实上它本身是没有自动刷新浏览器的功能的:
安装webpack-dev-server
npm install webpack-dev-server -D
修改配置文件,启动时加上serve参数:
packjson.js文件中
"scripts": {
"build": "webpack --config webpack.config.js",
"serve": "webpack serve --config webpack.config.js"
},
webpack.config.js文件中
module.exports = {
devServer: {
}
}
webpack-dev-server 在编译之后不会写入到任何输出文件,而是将 bundle 文件保留在内存中。 事实上webpack-dev-server使用了一个库叫memfs(memory-fs webpack自己写的)
什么是HMR?
HMR通过如下几种方式,来提高开发的速度:
如何使用HMR呢?
修改webpack.config.js配置
module.exports = {
devServer: {
hot: true,
}
}
浏览器的控制台会出现下面的提示
[HMR] waiting for update signal from wDs.. .
[WDS] Hot Module Replacement enabled.
但是当修改了某一个模块的代码时,依然是刷新的整个页面, 这是因为需要去指定哪些模块发生更新时,进行HMR;
// 指定哪一个模块需要HMR
if (module.hot) {
module.hot.accept("./utils/demo.js", () => {
console.log("demo模块发生了更新")
})
}
有一个问题:在开发其他项目时,是否需要经常手动去写入 module.hot.accpet相关的API呢?比如开发Vue、React项目,修改了组件,希望进行热更新,这个时候应该如何去操作呢?
事实上社区已经针对这些有很成熟的解决方案了:
host设置主机地址:
localhost 和 0.0.0.0 的区别:
port设置监听的端口,默认情况下是8080
open是否打开浏览器:
compress是否为静态文件开启gzip compression。 默认值是false,可以设置为true;
目前所有的webpack配置信息都是放到一个配置文件中的:webpack.config.js
那么,在启动时如何可以区分不同的配置呢?
packjson.js的关键代码如下
"scripts": {
"build": "webpack --config ./config/webpack.prod.config.js",
"serve": "webpack serve --config ./config/webpack.dev.config.js"
}
之前编写入口文件的规则是这样的: ./src/index.js,但是如果的配置文件所在的位置变成了 config 目录,是否应该变成 …/src/index.js呢?
context的作用是用于解析入口(entry point)和加载器(loader):
const path = require("path")
module.exports = {
context: path.resolve(__dirname,"./") //context是配置文件所在目录
entry: "../src/index.js", //或者main./src/main.js"
}
const path = require("path")
module.exports = {
context: path.resolve(__dirname,"../") //context是上一个目录
entry: "./src/index.js", //或者main./src/main.js"
}
创建三个文件:
在终端输入命令
npm install webpack-merge -D
webpack.dev.config.js
const { merge } = require("webpack-merge")
const commonConfig = require("./webpack.comm.config")
module.exports = merge(commonConfig, {
mode: "development",
devServer: {
hot: true,
// host: "0.0.0.0",
// port: 8888,
// open: true
// compress: true
}
})
webpack.prod.config.js
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const { merge } = require("webpack-merge")
const commonConfig = require("./webpack.comm.config")
module.exports = merge(commonConfig, {
mode: "production",
output: {
clean: true
},
plugins: [
new CleanWebpackPlugin()
]
})
webpack.comm.config.js
const path = require("path")
const { VueLoaderPlugin } = require("vue-loader/dist/index")
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { DefinePlugin } = require("webpack")
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "../build")
},
resolve: {
extensions: [".js", ".json", ".vue", ".jsx", ".ts", ".tsx"],
alias: {
utils: path.resolve(__dirname, "../src/utils")
}
},
module: {
rules: [
{
test: /\.css$/,
use: [ "style-loader", "css-loader", "postcss-loader" ]
},
{
test: /\.less$/,
use: [ "style-loader", "css-loader", "less-loader", "postcss-loader" ]
},
{
test: /\.(png|jpe?g|svg|gif)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 60 * 1024
}
},
generator: {
filename: "img/[name]_[hash:8][ext]"
}
},
{
test: /\.js$/,
use: [
{
loader: "babel-loader"
}
]
},
{
test: /\.vue$/,
loader: "vue-loader"
}
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
title: 测试项目",
template: "./index.html"
}),
new DefinePlugin({
BASE_URL: "'./'",
coderwhy: "'why'",
counter: "123"
})
]
}