前端工程化基础(三):Webpack基础

Webpack和打包过程

学习webpack主要是为了了解目前前端开发的整体流程,实际开发中,我们并不需要去手动配置,因为框架的脚手架都已经帮助我们完成了配置

内置模块path

该模块在Webpack中会经常使用

从路径中获取信息

js 复制代码
const path = require("path");
const pathStr = "D:/Mrzhang/Study/前端/node/code/zc_test/src/index.js";

//获取文件的父文件夹
console.log(path.dirname(pathStr)); //D:/Mrzhang/Study/前端/node/code/zc_test/src
//获取文件名
console.log(path.basename(pathStr)); //index.js
//获取扩展名
console.log(path.extname(pathStr));//.js

将多个路径拼接在一起(相对路径)

js 复制代码
const path = require("path");
const pathStr1 = "./src/view";
const pathStr2 = "../index.js";
const pathStr3 = "./index.js";

console.log(path.join(pathStr1, pathStr2)); //src\index.js
console.log(path.join(pathStr1, pathStr3)); //src\view\index.js

将多个路径拼接在一起(返回绝对路径)

  • 使用 **path.resolve()**方法,进行拼接
  • 当遇到 /xxx即为终止的解析,生成绝对路径
  • 在 **resolve()**方法中,里面的路径,会从右往左进行解析,直到生成一个绝对路径就会停止
  • 在所有 路径都解析完成之后,还没有生成绝对路径,就会使用当前工作目录
  • 路径中零长度的path会被忽略
js 复制代码
const path = require("path");

console.log(path.resolve("/src", "/txt.js")); //在"txt.js"就会停止解析 D:\txt.js
console.log(path.resolve("/src", "./txt.js")); // 在"/src"停止解析,D:\src\txt.js
console.log(path.resolve("/src/view", "../txt.js")); //D:\src\txt.js

认识Webpack

  • 官方的解释:Wevpack是一个静态的模块化打包工具,为现代的JS应用程序
  • 实际上会将我们编写的代码,打包成静态的资源
  • 打包:webpack可以帮助我们进行打包,它是一个打包工具
  • 静态:webpack可以将我们的代码打包成静态资源
  • **模块化:**webpack默认支持各种模块化开发,ESModule、CommonJS,AMD等
  • **现代的:**因为前端的不断发展,面临着各种各样的问题,催生了webpack的出现

Webpack使用前提

webpack的中文官方文档 中文文档

  • Webpack的运行是依赖Node环境的,所以电脑上需要右Node环境

Webpack的安装

  • webpack的安装目前分为两个:webpack和webpack-cli
  • webpack:主要用于代码中使用,通过代码对代码进行打包
  • webpack-cli:主要用于命令行中使用,通过命令行对代码进行打包
  • npm install webpack webpack-cli进行局部安装,若有需要可以进行全局安装

Webpack配置文件

  • 当我们在命令行执行 webpack命令,Webpack会默认去寻找目录中的 src/index.js文件
  • 并将该文件以及该文件引用的其他依赖进行打包,生成 dist文件夹 ,里面包含 main.js
  • 而默认的打包行为,不能满足我们的需求,因此,这时候可以在项目目录中创建webpack的配置文件 webpack.config.js
js 复制代码
const path = require("path");

//导出配置信息
//因为webpack基于node,所以使用CommonJS
module.exports = {
    //需要对哪个文件进行打包
  entry: "./src/main.js",
    //打包后的文件名,文件夹名称以及路径
  output: {
    filename: "bundle.js",
    //这里的path需要使用绝对路径,因此需要使用node中的path模块
    path: path.resolve(__dirname, "./dist"),
  },
};
  • 当我们在命令行输入 npx webpack

    • webpack就会寻找 webpack.config.js中的配置信息,完成代码的打包
  • 而每次输入 npx webpack 会很麻烦,因此,我们可以在 package.json 文件中的 scripts属性进行配置

js 复制代码
"scripts": {
    "build":"webpack"
  },
  • 之后我们就可以通过输入 npm run build进行文件的打包

css-loader的使用

Webpack默认是可以打包js文件的,但是对于其他文件在默认情况下不能进行打包

因此在打包其他文件的时候,需要用到对应文件的loader

css也不例外

  • 首先应当先安装 css-loader npm install css-loader
  • 安装完成后,需要在 webpack.config.js 进行配置
    • 目的是告诉webpack在遇到 css文件的时候,使用哪个loader
    • module.exports中创建module对象
    • module对象中,创建rules规则数组
    • rules数组中,创建一个又一个的对象,用于告诉webpack识别什么文件,使用什么loader
    • 对象中,使用test设置识别的文件,use使用相关loader
    • loader有多个内容的时候,是从后往前识别的,先识别后面,再识别前面
js 复制代码
const path = require("path");

//导出配置信息
//因为webpack基于node,所以使用CommonJS
module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    //这里的path需要使用绝对路径,因此需要使用node中的path模块
    path: path.resolve(__dirname, "./dist"),
  },
  //在module设置不同文件的loader
  module: {
    //因为loader会有很多,所以采用数组的方式
    rules: [
      {
        //告诉webpack匹配什么文件
        //在后面使用正则表达式
        test: /\.css$/,
        //使用什么laoder处理,
        //使用数组类型,因为一个文件有可能使用多个loader
        //css-loader仅是可以识别css文件,并不能将样式添加进去
        //style-loader是将样式添加到元素中
        //因为先识别css-loader,所以要写在后面
        use: [{ loader: "style-loader" }, { loader: "css-loader" }],
      },
    ],
  },
};

对less文件处理

与处理css文件类似

  • 首先通过 npm install less-loader安装less-loader
  • 之后对 webpack.config.js进行配置
js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [{ loader: "style-loader" }, { loader: "css-loader" }],
      },

      {
        //匹配less文件
        test: /\.less$/,
        //先对less文件进行解析
        //将less文件生成的css进行解析
        //最后将样式进行解析
          //这是简写
        use: ["style-loader", "css-loader", "less-loader"],
      },
    ],
  },
};

postcss-loader

这是一个工具,可以通过引入插件的方式,将我们写的css,自动做一个浏览器的适配,注意,需要安装相关插件

  • 首先使用 npm install postcss-loader安装post-loader
  • 之后在 module中引入 post-loader即可
js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [{ loader: "style-loader" }, { loader: "css-loader" },{loader:"postcss-loader"}],
      },

      {
        //匹配less文件
        test: /\.less$/,
        //先对less文件进行解析
        //将less文件生成的css进行解析
        //最后将样式进行解析
          //这是简写
        use: ["style-loader", "css-loader", "less-loader"],
      },
    ],
  },
};
  • 但是这样引入,并不能实现 css样式浏览器适配的打包,需要安装其余的插件

  • 通过 npm install autoprefixer安装插件即可

  • 之后对 postcss-loader进行配置

js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: "style-loader" },
          { loader: "css-loader" },
          {
            loader: "postcss-loader",
            //对某个loader进行单独的配置
            options: {
              //loader中设置使用的插件
              postcssOptions: {
                plugins: ["autoprefixer"],
              },
            },
          },
        ],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
    ],
  },
};
  • 同时 postcss-loader的配置可以单独使用一个文件

  • 创建 postcss.config.js

    • 在webpack.config.js使用 **loader:"postcss-loader"**会自动查找 postcss.config.js配置文件
js 复制代码
module.exports = {
  plugis: ["autoprefixer"],
};

//在webpack.config.js文件中,直接使用loader:"postcss-loader"即可

postcss-preset-env

上面我们用到了postcss的一个插件,而postcss-preset-env是将常用的插件集成到了一起

  • 此插件,继承了postcss常用的插件,包含上面提到过的 autoprefixer
  • 使用 npm install postcss-preset-env安装插件
  • webpack.config.js文件中使用该插件
js 复制代码
module.exports = {
  plugis: ["post-preset-env"],
};

Webpack打包图片

在webpack环境中,每一个文件都是模块,只需要引入模块即可

import testImg from "./img/test.jpg";

基本使用

  • 在webpack5之前对图片资源进行打包的时候,是需要安装一些loader的,raw-loader url-loader file-laoder

  • 在webpack5之后,我们可以直接使用 **资源模块类型(asset module type)**来替代上面的loader,即不用单独安装以上的loader

  • 我们仅需在 webpack.config.js的module属性中完成配置即可

js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
  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)/,
        type: "asset",
      },
    ],
  },
};

认识 asset module type

  • 在上面的配置中,我们设置了type:asset

  • type的类型有以下设置

    • **asset/resource:**发送一个单独的文件并导出URL
      • 之前通过file-loader实现
    • **asset/inline:**导出一个资源的data URI
      • 之前通过url-loader实现
    • **asset/source:**导出资源的源代码
      • 之前通过raw-loader实现
    • asset :在导出一个data URI和发送一个单独的文件之间自动选择
      • 之前通过url-loader,并且配置资源体积限制实现
  • asset/resource:使用该设置,会将图片打包成单独的单独的文件,放在dist文件夹中,通过url进行引入

    • 缺点就是,每一张图片都会进行一次网络请求,图片资源过多的时候,网络请求就会过多
  • **asset/inline:**使用该设置,会将图片设置成base64编码的格式,放在 bundle.js 文件中
    • 缺点就是,当图片资源过大的时候,会增加bundle.js文件的体积,造成下载资源缓慢
  • asset :会根据图片资源的大小,去判断打包成新的文件,还是打包成base64编码格式
    • webpack.config.js中进行设置
js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
  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)/,
        type: "asset",
        //设置多大的图片会进行base64编码
        parser: {
          dataUrlCondition: {
            //单位是byte,60*1024代表60kb
            //60kb之前会生成base64编码
            //大于60kb会打包成单独的文件
            maxSize: 60 * 1024,
          },
        },
      },
    ],
  },
};

对打包资源图片进行重命名

  • webpack.config.js中进行设置
  • 通过 generator进行设置
js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
  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)/,
        type: "asset",
        //设置多大的图片会进行base64编码
        parser: {
          dataUrlCondition: {
            maxSize: 60 * 1024,
          },
        },
        generator: {
          //占位符
          //name:源文件名
          //ext:文件名的后缀.png  .jpg
          //hash:webpack生成的hash
          //前面可以加上路径,代表打包之后,放到哪个文件夹中
          filename: "img/[name]_[hash][ext]",
        },
      },
    ],
  },
};

Webpack对js代码的babel处理

我们知道,webpack默认会对js文件进行打包的,但是仅仅是将代码进行压缩以及丑化

并不能将ES5+的代码转换成ES5的代码,保持浏览器的兼容

因此这时候需要用到babel工具

Babel工具

  • Babel是一个 **工具链,**主要用于就浏览器或者环境中将 ES5+的代码转换成ES5的代码
  • postcss工具类似,可以单独使用,不用借助于Webpack
  • 此处主要学习Webpack中的babel设置
  • 在webpack中使用 npm install babel-loader安装Babel工具

Babel预设babel/preset-env

常见的预设有三个env react TypeScript

  • 与postcss-loader类似,我们可以单独安装插件进行单独的配置
  • 但是随着插件数量的增多,有了预设插件 npm install @babel/preset-env
  • 安装完成之后,创建 babel.config.js文件,在里面完成配置
js 复制代码
module.exports = {
  presets: ["@babel/preset-env"],
};
  • webpack.config.js中的配置
js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
  module: {
    rules: [
      {
        //对js文件使用babel-loader工具
        test: /\.js/,
        //会自动去寻找babel.config.js中的设置
        use: ["babel-loader"],
      },
      {
        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)/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 60 * 1024,
          },
        },
        generator: {
          filename: "img/[name]_[hash][ext]",
        },
      },
    ],
  },
};

Webpack文件路径的解析和配置

  • 在我们实际发开中,会引入很多不同的依赖,通过 import/require的方式进行引入
  • 而webpack通过 enhanced-resolve模块对我们引入文件的路径进行一个解析
  • webpack能够解析三种文件路径
    • 绝对路径
      • 此种路径不会再做解析
    • 相对路径
    • 模块路径 (require("vue"))
      • 在resolve.modules中指定所有目录的检索模块
      • 默认值是["node_modules"],所以默认会从 node_modules中查找相应的文件
  • 那么怎么区分是文件还是文件夹呢

import {name} from "./until"

import {name} from "./until.js"

  • 如果是一个文件:
    • 如果文件具有扩展名,则直接打包文件
    • 否则,将会使用resolve.extensions选项作为文件扩展名的解析
js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
   //对文件会自动进行添加后缀
   //即我们写出import {name} from "./until"这样的代码,会在until后面自动拼接extensions数组里面的内容
  resolve: {
      extensions: [".js", ".json", ".jsx", ".vue"],
      alias: {
          //最好使用绝对路径
          //现在 /untils就代表了.src/untils
          utils: path.resolve(__dirname, ".src/untils"),
      },
  },
  module: {
    rules: [
    ],
  },
};
  • 如果是一个文件夹
    • 会在文件夹中根据 resolve.mainFiles配置选项中指定的文件顺序查找
    • 默认值是 [index]
    • 再根据 resolve.extensions解析扩展名

Webpack常见的插件和模式

认识plugin

  • 很多人会吧 plugin插件Loader弄混
  • Loader是用于特定的模块类型进行转换:如对.css .vue .jsx等文件进行转换
  • plugin可以用于更加广泛的任务,比如打包的优化,资源的管理,环境变量的注入等等

CleanWebpackPlugin

当我们修改了代码,重新打包的时候,需要手动的清除dist,再重新打包才是最新的

我们可以借助 CleanWebpackPlugin插件,完成手动清除dist文件夹的操作

  • 首先,我们先安装此插件 npm install clean-webpack-plugin -D

  • 在 webpack.config.js文件中完成配置即可

js 复制代码
const path = require("path");
//引入插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
    //使用插件
  plugins: [new CleanWebpackPlugin()],
  resolve: { },
  module: {
    rules: [],
  },
};

HtmlWebpackPlugin

在之前的学习中,当我们打包一个项目,生成的dist文件中并没有html文件,此插件的目的就是自动生成一个html文件

  • 首先通过 npm install html-webpack-plugin -D安装此插件
  • 之后再 webpack.config.js 文件中使用此插件
    • 此插件可以传入 title (设置html标题)、template(设置使用html的模板)
js 复制代码
const path = require("path");
//引入插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
    //使用插件
  plugins: [
      new CleanWebpackPlugin(),
  	  new HtmlWebpackPlugin({
      title: "zhangcheng",
      //自己引用模板的路径
      //   template: "相对路径",
    }),
  ],
  resolve: { },
  module: {
    rules: [],
  },
};

DefinePlugin的介绍

此插件已经集成到了 webpack中,因此我们直接引入即可

  • 此插件的目的是,在打包代码的过程中,生成全局变量
  • 此插件默认配置了 process.env.NODE_ENV用于区分开发环境和生成环境的
js 复制代码
const path = require("path");
//引入插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { DefinePlugin } = require("webpack");

module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
    //使用插件
  plugins: [
      new CleanWebpackPlugin(),
  	  new HtmlWebpackPlugin({
      title: "zhangcheng",
      //自己引用模板的路径
      //   template: "相对路径",
    }),
       new DefinePlugin({
      //使用key:value形式
      //value中会当成js代码
      counter: "1+1", //2
      counterStr: "'1+1'", //1+1字符串
    }),
  ],
  resolve: { },
  module: {
    rules: [],
  },
};

Mode配置

  • Mode配置选项,可以告知 webpack 使用相应模式的内置优化
    • 默认值是 production(什么都不配置的情况下)
    • 可选值有:none|development|production
js 复制代码
const path = require("path");


module.exports = {
    //Mode配置项
    mode:"development"
    entry: "./src/main.js",
    output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "./dist"),
},
    //使用插件
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: "zhangcheng",
            //自己引用模板的路径
            //   template: "相对路径",
        }),
        new DefinePlugin({
            //使用key:value形式
            //value中会当成js代码
            counter: "1+1", //2
            counterStr: "'1+1'", //1+1字符串
        }),
    ],
        resolve: { },
            module: {
                rules: [],
            },
};

Webpack搭建一个本地服务器

前面的学习中,我们编写完成代码后,需要手动执行build命令,完成项目的打包,效率会很低

  • 通过Webpack搭建一个本地的服务器,代码发生变化的时候,就自动打包,并刷新浏览器

  • 需要借助webpack-dev-server来完成以上操作

  • 首先通过 npm install webpack-dev-server -D安装 webpack-dev-server

  • 在package.json文件的scripts中增加相应的脚本

js 复制代码
"scripts": {
    "build": "webpack",
    "serve": "webpack serve"
  },
  • 之后运行 npm run serve即可

  • 实际上webpack-dev-server会将代码打包到内存中,之后开启一个服务器,浏览器访问本地的服务器读取内存中的代码,并不会生成本地的文件

HMR模块热替换

  • 当我们只对某个模块发生了改变,则只会对改变的模块进行替换,添加以及删除等操作,从而无需刷新整个页面

  • HMR通过一下几种方式,来提高开发的效率

    • 不重新加载整个页面,这样可以保留某些应用程序的状态不丢失
    • 只更新需要变化的内容,节省开发的时间
    • 修改了css、js源代码,会立即在浏览器更新
  • 目前webpack是默认开启HMR的

    • 同时我们可以手动开启,在 webpack.config.js 文件中,配置 devServer属性
    js 复制代码
    devServer:{
        hot:true
    }
  • 在代码中,我们需要指定哪些模块发生变化时,进行HMR

js 复制代码
//判断是否开启了HMR
if(module.hot){
    module.hot.accept("./until.js",()=>{
        console.log("更新了")
    })
}

本地服务的配置

js 复制代码
devServer:{
    hot:true,
    //修改端口号
    port:8888
    //修改主机
    host:"0.0.0.0"
    //自动打开浏览器
    open:true
    //是否对文件进行压缩
    compress:true
}
相关推荐
黑客老陈13 分钟前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安18 分钟前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
暴富的Tdy1 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se1 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
m0_748235611 小时前
web 渗透学习指南——初学者防入狱篇
前端
z千鑫1 小时前
【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
前端·vue.js·node.js
m0_748250742 小时前
Web入门常用标签、属性、属性值
前端
m0_748230442 小时前
SSE(Server-Sent Events)返回n ,前端接收数据时被错误的截断【如何避免SSE消息中的换行符或回车符被解释为事件消息的结束】
前端
生产队队长3 小时前
项目练习:element-ui的valid表单验证功能用法
前端·vue.js·ui