20230515----重返学习-webpack-构建React工程化项目

8 篇文章 0 订阅
5 篇文章 0 订阅

day-070-seventy-20230515-webpack-构建React工程化项目

webpack

webpack-dev-server

webpack-dev-server跨域代理原理
  1. 首先webpack会对代码进行打包。
    • 打包结果大概为:
      • index.html
      • index.jqijvcjnd22015445.css
      • index.kjj.js
  2. webpack-dev-server开始运行。
    1. 在客户端本地启动一个web服务。
      • 假设:
        • 域名: 127.0.0.1 localhost
        • 端口号:3000
    2. web服务会对webpack打包后的文件进行处理,放到webpack的web服务器中。
    3. 客户端浏览器打开。
      1. 输入网址,如 http://127.0.0.1:3000/index.html ;
      2. 向web服务器发起http请求。
      3. web服务器给浏览器返回一些资源或数据。
      4. 客户端浏览器收到web服务器返回的资源,开始渲染页面。
  3. 后端服务器,与web服务器是跨域的。
    1. 接口地址:http://192.168.1.23:8000 ;
      • 接口路径,如:
        • /user/list
        • /user/info
    2. 与前端服务器是跨域的,所以客户端浏览器会给前端服务器发起一个请求。
    3. 前端服务器充当一个代理服务器,实现数据的跨域请求!
      • proxy跨域代理的原理。
      • 这里web服务器会根据前端在/webpack.config.js中的devServer.proxy中的内容来做代理请求的处理。
      • 这一步主要是把前端访问的本web服务器路径修改成要访问的后端服务器地址。
    4. web服务器充当代理服务器向真正的后端发请求。
      • 因为后端与后端之间默认是没有跨域限制的。
      • 也可以在这里写一个临时后台。
    5. 后端服务器向代理服务器返回数据。
    6. 前端服务器把后端服务器返回的数据,转发给回客户端服务器。
webpack-dev-server跨域代理配置
  1. 先安装webpack-dev-server这个插件。

  2. 配置开发服务器。

    • /webpack.config.js

      {
        // 配置开发服务器-得先安装webpack-dev-server这个插件。
        devServer: {
          host: "127.0.0.1",
          port: 3000,
          compress: true,
          open: true,
          proxy: {
            // 知乎服务器的代理。
            "/api": {
              // https://news-at.zhihu.com/api/4/news/latest
              target: "https://news-at.zhihu.com",
              changeOrigin: true,
      
              // `/api/4/news/latest`  --> `浏览器默认会加前端服务器的地址 http://127.0.0.1:3000`  --> `http://127.0.0.1:3000/api/4/news/latest`  --> `前端服务器转为代理地址`  --> `https://news-at.zhihu.com/api/4/news/latest`
            },
            // 简书服务器的代理。
            "/inst": {
              // https://www.jianshu.com/asimov/subscriptions/recommended_collections
              target: "https://www.jianshu.com",
              changeOrigin: true,
              pathRewrite: {
                "^/inst": "",
              },
            },
          },
        },
      }
      
  3. 用webpack server启动webpack-dev-server服务。

    • 可能会报错,可能就是一些配置项没有。
      • 这主要是配置问题。
      • 或者是webpack-dev-server版本不一致。
        • 一般以1为单位降一个版本或升一个版本。

多文件多入口

  • 多入口中entry选项要用对象的格式。

    • 我们直接写出来的是 module,webpack 处理时是 chunk,最后生成浏览器可以直接运行的 bundle。
      • /webpack.config.js字符串格式

        {
          entry: "./src/index.js", //=>入口,多文件可以用对象。//相当于:entry: {main:"./src/index.js"},  
        }
        
  • output中文件名也要使用"[name].[hash:8].js"这类,让不同文件的文件名都不一致。

  • 要输出多少个html文件,就要在plugins使用多少次new HtmlWebpackPlugin(),每调用一次new HtmlWebpackPlugin()就生成一个html文件。

  • /webpack.config.js配置

    entry: {
      main:'./src/index.js',    //-> mian.1q2w3e4r.js
      login: '.src/login.js',       //-> login.2we3r45t.js
      //....
      // login/main 这些名字,称之为 chunk 名
    },
    output: {
      filename: "[name].[hash:8].js",//这里的name要用chunk名,否则可能会有造成不同的文件的文件名相同,进而造成冲突导致有些文件丢失。
      //...
    },
    // 使用插件。
    plugins: [
      // 作用:打包HTML页面,把打包后的bundle包,自动导入到html中...。
      // 要输出多少个html文件,就要在plugins使用多少次new HtmlWebpackPlugin(),每调用一次new HtmlWebpackPlugin()就生成一个html文件。
      new HtmlWebpackPlugin({
        title: "fang-title-webpack学习", //在模块中可以使用htmlWebpackPlugin.options.title来修改了。
        template: "./public/index.html", //要使用的模板html文件。
        minify: true, //是否要压缩html文件。
        favicon: "./public/favicon.ico", //要使用的网页图标。
      }),
    
      new MiniCssExtractPlugin({
        //=>设置编译后的文件名字
        filename: "main.[hash].css",
      }),
    
      // 作用:清除之前打包的文件。
      new CleanWebpackPlugin(),
    ],
    

插件

  • /webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
{
  /* 使用插件 */
  plugins: [
    // 作用:打包HTML页面;把打包后的bundle包,自动导入到html中...
    new HtmlWebpackPlugin({
      title: "珠峰培训-webpack学习",
      template: "./public/index.html",
      favicon: "./public/favicon.ico",
      minify: true,
    }),
    // 作用:清除之前打包的内容
    new CleanWebpackPlugin(),
    // 作用:抽离CSS单独进行打包
    new MiniCssExtractPlugin({
      filename: "bundle.[hash:8].css",
    }),
  ],
}

loader

  • 使用loader

    • 在module.rules数组中写,每个对象表示一类文件的处理。

    • 如果使用很多loader,则处理顺序:从下到上,从右到左…。

    • 默认对当前根目录下所有目录的文件都进行编译。

    • include: 指定只对那些目录进行编译。

    • exclude:指定对那些目录不进行编译。

      const MiniCssExtractPlugin = require("mini-css-extract-plugin");
      {
        /* 
          使用Loader
            + 如果使用很多Loader,则处理顺序:从下->上 、从右->左...
            + include: 指定只对哪些目录进行编译  path.resolve(__dirname, 'src')
            + exclude: 指定哪些文件不编译  /node_modules/
          */
        module: {
          rules: [
            // 处理Css&Less的
            {
              test: /\.(css|less)$/i,
              exclude: /node_modules/,
              use: [
                // 'style-loader', //把编译后的css以内嵌式插入到页面中
                MiniCssExtractPlugin.loader,
                "css-loader", //处理css中的特殊语法,例如:url...
                "postcss-loader", //给css设置前缀,以此来实现浏览器兼容
                "less-loader", //把less编译为css
              ],
            },
            // 处理JS
            {
              test: /\.(js|jsx|ts|tsx)$/i,
              include: path.resolve(__dirname, "src"),
              //use: ["babel-loader"],
              use: [{
                  loader: 'babel-loader',
                  options: {
                      presets: ['@babel/preset-env']
                  }
              }]
            },
          ],
        },
      }
      
  • babel-loader插件的外置:

    • /webpack.config.js

      {
        module: {
          rules: [
            {
              test: /\.(js|jsx|ts|tsx)$/i,
              include: path.resolve(__dirname, "src"),
              use: [{
                  loader: 'babel-loader',
                  options: {
                      presets: ['@babel/preset-env']
                  }
              }]
            },
          ],
        },
      }
      
    • 等价于

      • /webpack.config.js

        {
          module: {
            rules: [
              {
                test: /\.(js|jsx|ts|tsx)$/i,
                include: path.resolve(__dirname, "src"),
                use: ["babel-loader"],
              },
            ],
          },
        }
        
      • /babel.config.js

        module.exports = {
            presets: ['@babel/preset-env']
        }
        

优化项

  • /webpack.config.js
const CssMinimizer = require("css-minimizer-webpack-plugin");
const Terser = require("terser-webpack-plugin");
{
  /* 优化项 */
  optimization: {
    minimizer: [new CssMinimizer(), new Terser()],
  },
}

解析器

  • 主要做路径重定向。

    • 让webpack可以识别路径"@/“就是"src/”。进而可以访问到路径"@/"的资源。
  • /webpack.config.js

    {
      /* 解析器 */
      resolve: {
        alias: {
          "@/": path.resolve(__dirname, "src/"),//让webpack可以识别路径"@/"就是"src/"。进而可以访问到路径"@/"的资源。
        },
      },
    }
    
    • 不过这个只是是让webpack可以打包到的。在写代码时,还要求文本编辑器如vscode可以识别到"@/“就是"src/”,故而要配置/jsconfig.json;
      • /jsconfig.json

        {
          "compilerOptions": {
            "baseUrl": "./",
            "paths": {
              "@/*": [
                "src/*"
              ]
            }
          }
        }
        

webpack兼容问题

  • 在前端项目中,需要考虑的兼容问题:
    • 首先需要设置浏览器兼容列表:package.json

      {
          "browserslist": [
          "> 1%",
          "last 2 versions",
          "not ie <= 9"
        ]
      }
      
    • webpack的设置。

      • css3样式的兼容。
        • 思路:设置前缀。
      • ES6语法的兼容。
        • 思路:转换为ES5。
      • ES6内置API的兼容。
        • 思路:
          • 不使用这些内置API。
          • 对这些内置API或方法进行重写。

构建React工程化项目

步骤

  • 安装create-react-app

    npm i create-react-app -g //「mac需要加sudo」
    
  • 使用create-react-app创建一个项目

    create-react-app 项目名 
    
    create-react-app my-work 
    

项目说明

  • vue框架,所有的核心都在vue库中,所以只要导入vue就行了。

    import Vue from 'vue'
    
    • vue框架本身只能开发WebApp;但是我们可以在uni-app框架中,基于vue的语法,开发NativeApp!!
  • react框架不是类似于vue那样设计的,核心是分开的。

    • react 语法核心

      import React from 'react'
      
    • react-dom 构建web页面,即webApp。用于构建浏览器相关页面的。

      import ReactDOM from 'react-dom/client'
      
      • WebApp:H5页面。用来构建DOM的。
      • vue框架本身只能开发WebApp;但是我们可以在uni-app框架中,基于vue的语法,开发NativeApp!
    • react-native 构建NativeApp的,相当于用js,可以创建出安卓与ios系统的DOM。

      • 简称RN,也有人叫RN框架。
  • react框架的配置项。

    • create-react-app 为了让创建的项目看起来更简单/整洁,把webpack的所有配置,全部都隐藏到了node_modules中
      • react-scripts 是React内部自己封装的模块,属于对webpack的统一管理「对打包及预览的管理」
        • @vue/cli脚手架也是这样干的,配置文件都放到vue.config.js了。
  • web-vitals是用来做性能测试。

  • 默认可执行脚本

    • start 开发服务器运行
    • build 打包文件
    • test 单元测试
    • eject 暴露配置项
      • 一旦暴露出来,就能再隐藏回去了!
      • 基本上一定会暴露出来,只用默认的不太好。如跨域就得自己配置。

词法规范

  • 不论是@vue/cli还是create-react-app等脚手架,创建好的项目中,基本上都包含 Eslint 的配置!
    • Eslint :词法检测「检测编写的代码是否符合既定的规范」
      • 浏览器本身在运行JS的时候,也会进行词法检测,只不过其只会检测语法是否符合ECMAScript的规范,不符合规范的,说明语法写错了,报SyntaxError.
        • 但是 Eslint ,它不仅仅可以检测错误的语法,而且一些即便没有错(浏览器可以正常运行的),但是它只要认为这样写不好,也会检测成为错误的语法!

          let a = 12
          //如果后续都没有使用这个a,则会给出检测的警告错误:声明但是没有使用!
          
        • 如果格式化有问题,问公司中配置了那个规则的人要。

配置项

  • 不论是 create-react-app 还是 @vue/cli,都把webpack的配置项隐藏到了 node_modules 中了!
    • 如果发现,默认的配置项,没有完全符合我们的要求,此时我们要修改默认的配置项!
      1. @vue/cli

        • 在根目录下创建 vue.config.js ,按照官方要求去修改即可
        • 降低了开发者的学习门槛,即便webpack知识不咋地,也可以完成一些基础配置的更改;但凡webpack稍微好点,直接想改啥就改啥!!
      2. create-react-app

        • react作者是没有尤雨溪贴心的,他认为你连webpack都不会,你还做啥前端!

        • 所以如果我们想修改默认的配置项,create-react-app的处理办法:把默认的配置项给开发者暴露出来即可!!

          npm run eject    //-> 有个特点:一但暴露出来,就不能再隐藏回去了
          
          • 得先确认是否是暴露,输入yes按回车就好了。

            • 「如果项目有git仓库」我们刚才改了代码,暴露的结果是,会新增很多文件和文件夹,为了防止新增的这些东西,对我们自己写的代码有影响,需要我们提前把修改的东西,提交到git仓库的历史区!!
          • 之后就会在项目中多出一些东西,同时该命令还会一些文件夹及文件出现,以及修改了/package.json

            • /config/
              • /config/jest/
                • /config/jest/babelTransform.js
                • /config/jest/cssTransform.js
                • /config/jest/fileTransform.js
              • /config/webpack/
                • /config/webpack/persistentCache/
                  • /config/webpack/persistentCache/createEnvironmentHash.js
              • /config/env.js 环境相关的。
              • /config/getHttpsConfig.js
              • /config/modules.js
              • /config/paths.js
              • /config/webpack.config.js webpack的配置项。
              • /config/webpackDevServer.config.js webpack-dev-server的配置项。
            • /scripts/ 脚本文件,用nodejs来写的。
              • /scripts/build.js 执行yarn build时执行的,里面有些参数可以调整。
              • /scripts/start.js 执行yarn start时执行的,里面有些参数可以调整。
              • /scripts/test.js
            • /package.json
              • dependencies 中多了很多依赖。
              • scripts 命名被必定了,少了eject命名。
              • jest 单元调试。
              • babel babel的配置。
                • babel语法转换的语法包:@babel/preset-env
                • react项目中,实现ES6转ES5的语法包:"babel-preset-react-app“ 对 @babel/preset-env 重写,目的是为了支持 JSX 语法编译和转换。
        • 如果需要改啥,直接去源码上改就好了「但是要求开发者需要掌握webpack」

base编码

  • 用src非base路径,会向服务器发起一个请求。
    • 之后浏览器把图片编码成base格式。
    • 之后图片会渲染到页面上。
  • 用src里写base,可以减少请求。
    • 不过去造成html文件变大。
    • 同时会造成html标签结构变难看,一大块地方都是那img标签。
    • 同时图片处理成base编码还比较难看。

react的webpack配置

  • react的webpack配置分散在不同的文件的不同地方。
    • 核心入口在/package.json中,通过npm run xxx执行它内部的脚本。
    • 之后在package.scripts脚本以nodejs来中运行/scripts/start.js/scripts/build.js
    • /scripts/start.js/scripts/build.js中引入了webpack及webpack的配置以及在这里调用了/config/中的各个配置或nodejs函数。经过各种处理后返回一个webpack配置对象。
    • webpack依据/scripts/start.js/scripts/build.js中返回的webpack配置对象来进行编译,一般是从入口文件开始,入口文件默认配置为/src/index.js,而从index.js开始,会以浏览器的模式来写及引入代码。
      • 特殊语法则是通过webpack的插件来补足,如jsx及less这一类的东西。
  • 不同地方的webpack常见配置修改。
    • 依照功能的修改:
      • process.env.NODE_ENV 是开发环境还是生产环境。
        • /scripts/start.js/scripts/build.js中修改。
      • process.env.HOST 开发环境中,本地启动服务器的域名。
        • /scripts/start.js中修改。
      • process.env.PORT 开发环境中,本地启动服务器的端口号(默认3000)。
        • /scripts/start.js中修改。
      • process.env.HTTPS 开发环境中,本地启动服务器的协议是否使用https协议。
        • /scripts/start.js中修改。
      • WARN_AFTER_BUNDLE_GZIP_SIZE 在bundle压缩大小超过之后发出警告。
        • 直接写出来的是 module,webpack 处理时是 chunk,最后生成浏览器可以直接运行的 bundle。
        • /scripts/build.js中修改。
      • WARN_AFTER_CHUNK_GZIP_SIZ 在chunk压缩大小超过之后发出警告。
        • /scripts/build.js中修改。
      • /config/paths.js 中的各项常量
        • dotenv: resolveApp('.env')
        • appPath: resolveApp('.')
        • appBuild: resolveApp(buildPath)
        • appPublic: resolveApp('public')
        • appHtml: resolveApp('public/index.html')
        • appIndexJs: resolveModule(resolveApp, 'src/index') 打包入口。
        • appPackageJson: resolveApp('package.json')
        • appSrc: resolveApp('src')
        • appTsConfig: resolveApp('tsconfig.json')
        • appJsConfig: resolveApp('jsconfig.json')
        • yarnLockFile: resolveApp('yarn.lock')
        • testsSetup: resolveModule(resolveApp, 'src/setupTests')
        • proxySetup: resolveApp('src/setupProxy.js')
        • appNodeModules: resolveApp('node_modules')
        • appWebpackCache: resolveApp('node_modules/.cache')
        • appTsBuildInfoFile: resolveApp('node_modules/.cache/tsconfig.tsbuildinfo')
        • swSrc: resolveModule(resolveApp, 'src/service-worker')
        • publicUrlOrPath: publicUrlOrPath
      • shouldUseSourceMap 是否使用source-map,用于取消生产环境下source-map调试文件的创建,以此来加快打包的速度。
        • config/webpack.config.js中配置。
      • drop_console与drop_debugger 去掉调试相关的代码。
        • config/webpack.config.js中webpack配置项中optimization.minimizer中TerserPlugin插件配置项terserOptions.compress中配置。
      • 配置@等路径别名
        • config/webpack.config.js中webpack配置项中resolve.alias中配置。
          • 不过这个只是让webpack能够解析及编译"@/*"这类的路径,并不能让vscode等提示工具也能提示出对应路径的文件,需要在根目录配合jsconfig.json这个文件来进行处理。
            • /jsconfig.json

              {
                  "compilerOptions": {
                      "baseUrl": "./",
                      "paths": {
                          "@/*": [
                              "src/*"
                          ]
                      }
                  }
              }
              
              • 这个是让vscode等工具能够识别出"@/*"这类的路径,能在打出@这个符号之后提示在/src/*这个目录下有什么文件。
      • imageInlineSizeLimit 把多大的图片处理成base64编码。
        • config/webpack.config.js中配置。
        • 图片base64是前端性能优化一个非常重要的手段!
          • 传统加载图片,是一件比较消耗性能和时间的事情,我们需要:
            1. 向服务器发送请求,获取图片资源。
            2. 浏览器编码。
            3. 渲染。
          • 采用base64,则直接渲染即可,大大加快了图片渲染的速度!
            • 但是图片的BASE64码很多,会增加原有html/css文件的体积,而且如果需要手动base64,是不方便我们开发和维护~!
              • 所以:base64不要滥用!
              • webpack中可以把指定大小的图片,进行base64。
                • 只针对于访问的是本地的静态资源图片。网络的图片不能进行。
        • CSS预编译语言的处理。
          • react脚手架的预编译语言是scss,但想要使用less。
            • scss的loader依旧是sass-loader。
            1. 移除sass-loader,下载less与less-loader@8。

              • less-loader最新版不太兼容react脚手架,最好用旧一点的版本,如8.0.0版本。
              yarn remove sass-loader//移除sass-loader;
              yarn add less less-loader@8//下载less与less-loader@8.0.0;
              
              • config/webpack.config.js中配置。
                • 移除scss与sass相关的配置,改成less配置。
代码兼容解决
  • 浏览器的兼容处理
    • 2023年兼容处理主要方向
      1. CSS3的兼容
      2. ES6语法的兼容
      3. 部分ES6+内置API的兼容
    • 兼容步骤
      • 先在/package.json中配置基础browserslist选项。

        • /package.json

          {
            "browserslist": {
              "production": [
                ">1%",
                "last 2 versions",
                "not ie < 10"
              ],
              "development": [
                "last 1 chrome version",
                "last 1 firefox version",
                "last 1 safari version"
              ]
            }
          }
          
        1. CSS3的兼容
          • postcss-loader + autoprefixer + browserslist
        2. ES6语法的兼容
          • babel-loader + babel-preset-react-app + browserslist
          • 如果我们项目中,使用了一些如装饰器的特殊的语法,还需要一些额外的babel的插件来处理!
        3. 部分ES6+内置API的兼容
          • 安装react-app-polyfill插件。

            • react-app-polyfill是react对@babel/polyfill的重写。
          • 在入口文件/src/index.js中引入react-app-polyfill的一些js文件,如react-app-polyfill/ie11

            import "react-app-polyfill/ie11"
            
跨域代理
  • 跨域地址
  • 开发环境下,我们可以基于 webpack-dev-server 实现跨域代理。
    • 等到项目部署到服务器端,需要看服务器端是如何部署的。
      • 如果是基于nginx部署,则需要配置nginx的反向代理。
  • 基于 webpack-dev-server 实现跨域代理。
    1. 方案一:查找 /package.json 中的 proxy 字段。
      - 弊端:只能设置成为字符串
      - 不推荐
      - /package.json

      {
        "proxy": "https://news-at.zhihu.com/api/4"
      }
      
    2. 方案二: 在 src 下新建 setupProxy.js 文件,基于 http-proxy-middleware 实现跨域代理

      • 安装http-proxy-middleware插件。

        yarn add http-proxy-middleware
        
      • 新建src/setupProxy.js

        const { createProxyMiddleware } = require('http-proxy-middleware');
        module.exports = function (app) {
            app.use(
                createProxyMiddleware("/api", {
                    target: "http://127.0.0.1:7100",
                    changeOrigin: true,
                    ws: true,
                    pathRewrite: { "^/api": "" }
                })
            );
        };
        

设置环境变量

  • 在react的webpack默认配置项中,有很多操作,是基于环境变量来处理的
    • 常用环境变量
      • process.env.NODE_ENV 是开发环境还是生产环境
      • process.env.HOST 开发环境中,本地启动服务器的域名
      • process.env.PORT 开发环境中,本地启动服务器的端口号(默认3000)
      • process.env.HTTPS 开发环境中,本地启动服务器的协议是否使用https协议
      • process.env.PUBLIC_URL 项目打包静态根目录。
      • process.env.BUILD_PATH
    • 设置方案
      1. 方案一:基于 cross-env 把MAC和Window操作系统的设置方式统一化。

        yarn add cross-env
        
        • 这种方式,需要在执行npm脚本命令的时候配置!
          • 配置开发服务器端口。
        • 默认打包的时候,我们导入的资源,都是从服务器的根目录下开始的,这就要求:我们需要把打包的内容,部署到服务器的根目录下才可以「否则从根目录下,是找不到这些资源的」”虽然我们一般都部署到根目录。
          • 当期望可以调整一下:把访问资源的前缀路径,从 ”/“ 改为 ”./“(从当前目录查找),或者是一个CDN的地址!
      2. 方案二:基于 .env 文件,设置需要的环境变量。

        • 创建三个本地文件,用于存放环境变量。
          • .env用于存放公共的环境变量。
          • .env.development用于存放开发环境development的环境变量。
          • .env.production用于存放生产环境production的环境变量。
      3. 在对应脚本文件的nodejs文件入口中直接用修改环境变量。

进阶参考

  1. webpack-dev-server – 配置中文文档
  2. webpack-dev-server – npm
  3. webpack 中,module,chunk 和 bundle 的区别是什么?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值