zoukankan      html  css  js  c++  java
  • 650 webpack 搭建本地服务器:watch,webpack-dev-server,HMR,publicPath、contentBase,hotOnly,host,port、open、compress,Proxy,changeOrigin,resolve解析,extensions、alias

    为什么要搭建本地服务器?


    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 = {
      // watch: true,
      mode: "development",
      entry: "./src/index.js",
      output: {
        filename: "bundle.js",
        path: path.resolve(__dirname, "./build")
      },
      // 专门为webpack-dev-server配置
      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

    /**
     * 存在的问题:
     *  问题一: 每次修改源代码之后, 我们都需要重新执行npm run build
     *    * 通过watch监听源代码的变化
     * 
     * 目前的开发模式: 
     *    1.watch方案来监听文件的变化 
     *    2.通过live-server插件提供本地服务(当文件变化时,自动刷新页面)
     * 效率并不是特别高:
     *    1.对所有的源代码都重新进行编译
     *    2.编译成功后,都会生成新的文件(文件操作 file system)
     *    3.live-server属于VSCode插件(vim/webstorm) -> 不属于webpack给我们的解决方案
     *    4.live-server每次都会重新刷新整个页面
     * 
     *  webpack-dev-server: hot module replacement(HMR)
     */
    
    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");
    
    // 【module是全局对象。】
    if (module.hot) {
      module.hot.accept("./math.js", () => {
        console.log("math模块发生了更新~");
      });
    }
    
    // React的代码
    ReactDom.render(<ReactApp/>, document.getElementById("app"));
    
    // Vue的代码
    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 = {
      // watch: true,
      mode: "development",
      entry: "./src/index.js",
      output: {
        filename: "bundle.js",
        // 打包后的文件的输出目录
        path: path.resolve(__dirname, "./build"),
        // publicPath:在打包之后的静态资源前面进行一个路径的拼接,默认值是一个空字符串 【拼接:主机名 + publicPath + bundle.js】
        // js/bundle 会拼接成 -> ./js/bundle.js,通过相对路径访问
        // publicPath: "./"
        // publicPath: "/abc"
      },
      // 专门为webpack-dev-server
      // devServer为开发过程中, 开启一个本地服务
      devServer: {
        hot: true,
        hotOnly: true,
        // host: "0.0.0.0", // 经测试,不能通过 http://0.0.0.0:端口/ 进行访问
        // port: 7777,
        // open: true,
        compress: true,
        // 通过src与进入的静态资源会去配置的contentBase中查找【本地服务的路径是在"./why"】
        contentBase: path.resolve(__dirname, "./why"),
        watchContentBase: true, // abc.js代码改变后,自动刷新浏览器
        // 开发环境中,devServer的publicPath 和 output的publicPath一致
        // publicPath: "/abc",
        proxy: {
          // "/why": "http://localhost:8888"
          "/why": {
            // 映射,"/why"相当于"http://localhost:8888"
            target: "http://localhost:8888", 
            pathRewrite: {
              "^/why": ""
            },
            secure: false, // 支持https
            changeOrigin: true // 如果服务器做了验证,就要设置为true
          }
        },
        // historyApiFallback: 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模块发生了更新~");
      });
    }
    
    // React的代码
    ReactDom.render(<ReactApp/>, document.getElementById("app"));
    
    // Vue的代码
    new Vue({
      render: h => h(VueApp)
    }).$mount("#root");
    
    // axios网络请求
    // changeOrigin的解析:--> 因为使用了代码,默认情况下它的值是 http://localhost:8080,服务器接收来源的时候,如果不去对它做额外的配置,服务器会认为这次请求的来源就是 http://localhost:8080。本来应该是target对应的 "http://localhost:8888",但是做了代理,请求变成了http://localhost:8080。如果服务器没有对来源做校验,此时不会有问题。如果服务器为了防止通过代理的方式爬服务器的数据,做了校验,校验这次请求是不是在http://localhost:8888,发现是8080,不是8888,就不会返回数据,所以要改回成8888。用了第三方库,取代理服务器,把源换成target的值http://localhost:8888,服务器就会验证通过。
    axios.get("http://localhost:8080/why/moment").then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err);
    });
    


  • 相关阅读:
    iOS版打地鼠游戏源码
    OuNews 简单的新闻客户端应用源码
    安卓DJ113舞曲网应用客户端 项目源码(服务器+客户端)
    博客迁移
    iOS 多张图片保存到相册问题(add multiple images to photo album)
    【转】 iOS 学习之 NSPredicate 模糊、精确、查询
    iOS 设置图片imageView圆角——对图片进行裁剪
    iOS9的那些坑 — — WeiboSDK registerApp启动就崩溃
    关于Debug下的Log打印问题
    Runtime运行时学习(一)
  • 原文地址:https://www.cnblogs.com/jianjie/p/14526459.html
Copyright © 2011-2022 走看看