为什么要搭建本地服务器?
Webpack watch
webpack-dev-server
- cnpm install --save-dev webpack-dev-server
- 注意,脚本是 "serve": "webpack serve"
webpack-dev-middleware 【了解】
webpack-dev-middleware的使用
认识模块热替换(HMR)
开启HMR
框架的HMR
React的HMR
- cnpm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
Vue的HMR
- cnpm install vue-loader vue-template-compiler -D
HMR的原理
HMR的原理图
webpack.config.js
| const path = require('path'); |
| const HtmlWebpackPlugin = require('html-webpack-plugin'); |
| const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); |
| const VueLoaderPlugin = require('vue-loader/lib/plugin'); |
| |
| module.exports = { |
| |
| mode: "development", |
| entry: "./src/index.js", |
| output: { |
| filename: "bundle.js", |
| path: path.resolve(__dirname, "./build") |
| }, |
| |
| devServer: { |
| hot: true |
| }, |
| module: { |
| rules: [ |
| { |
| test: /\.jsx?$/i, |
| use: "babel-loader" |
| }, |
| { |
| test: /\.vue$/i, |
| use: "vue-loader" |
| }, |
| { |
| test: /\.css/i, |
| use: [ |
| "style-loader", |
| "css-loader" |
| ] |
| } |
| ] |
| }, |
| plugins: [ |
| new HtmlWebpackPlugin({ |
| template: "./index.html" |
| }), |
| new ReactRefreshWebpackPlugin(), |
| new VueLoaderPlugin() |
| ] |
| } |
package.json
| { |
| "name": "webpack_devserver", |
| "version": "1.0.0", |
| "description": "", |
| "main": "index.js", |
| "scripts": { |
| "build": "webpack", |
| "watch": "webpack --watch", |
| "serve": "webpack serve" |
| }, |
| "author": "", |
| "license": "ISC", |
| "devDependencies": { |
| "@babel/core": "^7.12.17", |
| "@babel/preset-env": "^7.12.17", |
| "@babel/preset-react": "^7.12.13", |
| "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", |
| "babel-loader": "^8.2.2", |
| "css-loader": "^5.0.2", |
| "html-webpack-plugin": "^5.2.0", |
| "react-refresh": "^0.9.0", |
| "style-loader": "^2.0.0", |
| "vue-loader": "^15.9.6", |
| "vue-template-compiler": "^2.6.12", |
| "webpack": "^5.23.0", |
| "webpack-cli": "^4.5.0", |
| "webpack-dev-server": "^3.11.2" |
| }, |
| "dependencies": { |
| "express": "^4.17.1", |
| "react": "^17.0.1", |
| "react-dom": "^17.0.1", |
| "vue": "^2.6.12", |
| "webpack-dev-middleware": "^4.1.0" |
| } |
| } |
index.js
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| import "./math"; |
| import React from 'react'; |
| import ReactDom from 'react-dom'; |
| import ReactApp from './App.jsx'; |
| |
| import Vue from 'vue'; |
| import VueApp from './App.vue'; |
| |
| console.log("Hello 哈哈哈"); |
| console.log("abc"); |
| |
| |
| if (module.hot) { |
| module.hot.accept("./math.js", () => { |
| console.log("math模块发生了更新~"); |
| }); |
| } |
| |
| |
| ReactDom.render(<ReactApp/>, document.getElementById("app")); |
| |
| |
| new Vue({ |
| render: h => h(VueApp) |
| }).$mount("#root"); |
App.vue
| <template> |
| <div id="app"> |
| <h2 class="title">{{ message }}</h2> |
| </div> |
| </template> |
| |
| <script> |
| export default { |
| data() { |
| return { |
| message: "Hello 哈哈哈", |
| }; |
| }, |
| }; |
| </script> |
| |
| <style scoped> |
| .title { |
| color: blue; |
| } |
| </style> |
App.jsx
| import React, { Component } from "react"; |
| |
| class App extends Component { |
| constructor(props) { |
| super(props); |
| |
| this.state = { |
| message: "Hello React", |
| }; |
| } |
| |
| render() { |
| return ( |
| <div> |
| <h2>{this.state.message}</h2> |
| </div> |
| ); |
| } |
| } |
| |
| export default App; |
babel.config.js
| module.exports = { |
| presets: [ |
| ["@babel/preset-env"], |
| ["@babel/preset-react"], |
| ], |
| plugins: [ |
| ["react-refresh/babel"] |
| ] |
| } |
output的publicPath
devServer的publicPath
devServer的contentBase
hotOnly、host配置
port、open、compress
Proxy代理
changeOrigin的解析
historyApiFallback
resolve模块解析
确实文件还是文件夹
extensions和alias配置
目录结构
webpack.config.js
| const path = require('path'); |
| const HtmlWebpackPlugin = require('html-webpack-plugin'); |
| const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); |
| const VueLoaderPlugin = require('vue-loader/lib/plugin'); |
| |
| module.exports = { |
| |
| mode: "development", |
| entry: "./src/index.js", |
| output: { |
| filename: "bundle.js", |
| |
| path: path.resolve(__dirname, "./build"), |
| |
| |
| |
| |
| }, |
| |
| |
| devServer: { |
| hot: true, |
| hotOnly: true, |
| |
| |
| |
| compress: true, |
| |
| contentBase: path.resolve(__dirname, "./why"), |
| watchContentBase: true, |
| |
| |
| proxy: { |
| |
| "/why": { |
| |
| target: "http://localhost:8888", |
| pathRewrite: { |
| "^/why": "" |
| }, |
| secure: false, |
| changeOrigin: true |
| } |
| }, |
| |
| historyApiFallback: { |
| rewrites: [ |
| {from: /abc/, to: "/index.html"} |
| ] |
| } |
| }, |
| resolve: { |
| extensions: ['.wasm', '.mjs', '.js', '.json', '.jsx', '.ts', '.vue'], |
| alias: { |
| "@": path.resolve(__dirname, "./src"), |
| "pages": path.resolve(__dirname, "./src/pages") |
| } |
| }, |
| module: { |
| rules: [ |
| { |
| test: /\.jsx?$/i, |
| use: "babel-loader" |
| }, |
| { |
| test: /\.vue$/i, |
| use: "vue-loader" |
| }, |
| { |
| test: /\.css/i, |
| use: [ |
| "style-loader", |
| "css-loader" |
| ] |
| } |
| ] |
| }, |
| plugins: [ |
| new HtmlWebpackPlugin({ |
| template: "./index.html" |
| }), |
| new ReactRefreshWebpackPlugin(), |
| new VueLoaderPlugin() |
| ] |
| } |
index.js
| import axios from 'axios'; |
| |
| import React from 'react'; |
| import ReactDom from 'react-dom'; |
| import ReactApp from './App.jsx'; |
| |
| import Vue from 'vue'; |
| import VueApp from './App.vue'; |
| |
| import "./math"; |
| |
| console.log("Hello Coderwhy"); |
| console.log("abc"); |
| |
| if (module.hot) { |
| module.hot.accept("./math.js", () => { |
| console.log("math模块发生了更新~"); |
| }); |
| } |
| |
| |
| ReactDom.render(<ReactApp/>, document.getElementById("app")); |
| |
| |
| new Vue({ |
| render: h => h(VueApp) |
| }).$mount("#root"); |
| |
| |
| |
| axios.get("http://localhost:8080/why/moment").then(res => { |
| console.log(res); |
| }).catch(err => { |
| console.log(err); |
| }); |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥
2020-03-12 372 python内置函数——sorted、filter、map、format
2020-03-12 371 python内置函数——eval、exec、compile
2020-03-12 370 python线程
2020-03-12 369 python进程
2020-03-12 368 操作系统简介
2020-03-12 367 python网络编程
2020-03-12 366 python面向对象进阶