Webpack学习笔记

Webpack

一、什么是 Webpack

是一个用于现代 JavaScript 应用程序的静态模块打包工具

静态模块:html、css、js、图片等固定内容的文件

打包:将静态模块的内容,压缩整合转译等(前端工程化)

  • 将 less/sass 转成 css 代码
  • 把 ES6+ 降级成 ES5
  • 支持多种模块标准语法

二、使用 Webpack

安装:

//保存到开发目录
npm i webpack webpack-cli --save-dev

设置自定义打包命令:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mDTPuj5f-1689042707139)(C:\Users\mzhj\AppData\Roaming\Typora\typora-user-images\image-20230705221304210.png)]

使用打包命令:

npm run <自定义打包命令>

修改 Webpack 打包入口和出口

  • 在根目录下新建 webpack.config.js 文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lxlgQdS5-1689042707140)(C:\Users\mzhj\AppData\Roaming\Typora\typora-user-images\image-20230705222749746.png)]

  • 修改:
const path = require('path');

module.exports = {
    //entry 为入口地址
  entry: path.resolve(__dirname, 'src/login/index.js'),
    
  output: {
      //出口地址
    path: path.resolve(__dirname, 'dist'),
      //出口文件名
    filename: './login/index.js',
    clean: true //生成打包内容之前,清空输出目录
  },
};

自动生成 html 文件:

使用插件 html-webpack-plugin:在Webpack 打包时生成 html 文件

安装插件(到开发环境)
npm i --save-dev http-webpack-plugin
在 webpack 配置文件中使用插件
const path = require('path');
//引用插件
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: path.resolve(__dirname, 'src/login/index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: './login/index.js',
    clean: true //生成打包内容之前,清空输出目录
  },
  //插件 生成 html 文件
  plugins: [new HtmlWebpackPlugin({
    //模板文件
    template: path.resolve(__dirname, 'public/login.html'),
    //输出文件
    filename: path.resolve(__dirname, 'dist/login/index.html')
  })]
};

打包 css 代码:

webpack 默认只能识别 js 代码

使用加载器 css-loader:解析 css 代码

使用加载器 style-loader:将解析后的 css 代码插入到 DOM

npm i css-loader

npm i style-loader
在 webpack 配置中使用加载器
module.exports = {
  //加载器 让 webpack 识别更多内容
  module: {
    rules: [
      {
        test: /\.css$/i,//解析 css 文件
        use: ["style-loader", "css-loader"],//从后往前运行
      },
    ],
  },
};

优化-提取 CSS 代码

好处:

css 文件可以被浏览器缓存,减少 js 文件体积

插件 mini-css-extract-plugin:提取 css 代码

  • 不能与 style-loader 一起使用

  • 建议与 css-loader 一起使用

安装:
npm install --save-dev mini-css-extract-plugin
在 webpack 配置中使用:
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  //生成 css 文件
  plugin: [new MiniCssExtractPlugin()]
  //加载器 让 webpack 识别更多内容
  module: {
    rules: [
      {
        test: /\.css$/i,//解析 css 文件
        use: [ MiniCssExtractPlugin.loader, "css-loader" ],//从后往前运行
      },
    ],
  },
};

优化-压缩 css

使用:css-minimizer-webpack-plugin 插件

安装:
npm i css-minimizer-webpack-plugin --save-dev
在 webpack 配置中使用:
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /.s?css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
  //自定义压缩功能
  optimization: {
    minimizer: [
      '...',//保留压缩 js 文件的功能
      new CssMinimizerPlugin(),//压缩 css 的功能
    ],
    minimize: true //允许在开发环境中使用
  },
  plugins: [new MiniCssExtractPlugin()],
};

打包 less 代码:

加载器 less-loader:把 less 代码编译成 css 代码

安装:
//安装 less-loader 需要安装 less
npm i less less-loader --save-dev
使用:
module: {
    rules: [
      {//提取 css 代码
        test: /\.css$/i,
        use: [ 
          MiniCssExtractPlugin.loader,
           "css-loader",
          ],//从后往前运行
      },
      {//提取 less 代码
        test: /\.less$/i,
        use: [ 
          MiniCssExtractPlugin.loader,
           "css-loader",
           "less-loader"
          ],//从后往前运行
      },
    ],
  },

打包图片:

资源模块: webpack5 内置模块(字体,图片等)打包,无需额外 loader

配置:
module: {
    rules: [
      {//提取 css 代码
        test: /\.(png|jpg|jpeg|gif)$/i,
        type: 'asset',//通用 大于 8kb 为 resource 小于为 inline
        generator: {
            //默认以 output 为基路径
            filename: 'assets/[hash][ext][query]'
            //占位符 [hash] 得到映射的数字字母组合的字符串
            //占位符 [ext] 使用当前模块原本的占位符:.png/.jpg等
            //占位符 [query] 保留引入文件时的查询参数(只有URL生效)
        }
      },
    ],
  },

inline:导出一个data URI (base64 字符串)压入 js 文件

resource:发送一个单独的文件并导出 URL 地址

三、搭建开发环境

配置 webpack-dev-server 快速开发应用程序

作用:启动 Web 服务,自动检测代码变化,热更新到网页

**注意:**dist 目录和打包内容是保存在内存中的(更新快

在 webpack 配置文件中设置为开发模式

module.exports = {
    mode: 'development'
}

开发工具:

  • watch mode(观察模式)

通过 npm run watch 启动,他会一直监听代码的变化并修改,但是浏览器的效果需要刷新

在 package.json 文件中添加

"watch": "webpack --watch",

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sNAOXmyw-1689042707141)(C:\Users\mzhj\AppData\Roaming\Typora\typora-user-images\image-20230706135445276.png)]

  • webpack-dev-server

提供了一个基本的 web server,并且具有 live reloading(实时重新加载) 功能

安装

npm install --save-dev webpack-dev-server

在 package.json 中配置自定义命令:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack serve --open"
  },

注意:

  • webpack-dev-server 借助 http 模块创建 8080 默认 web 服务

  • 默认以 public 文件夹作为服务器根目录

  • webpack-dev-server 根据配置,打包相关代码在内存中,作为服务器根目录,以 output.path 的值作为服务器根目录(所以可以直接自己拼接访问 dist 目录下的内容)

  • webpack-dev-middleware

webpack-dev-middleware 是一个封装器(wrapper),它可以把 webpack 处理过的文件发送到一个 server。webpack-dev-server 在内部使用了它,然而它也可以作为一个单独的 package 来使用,以便根据需求进行更多自定义设置。

四、打包模式

告知 webpack 使用相应模式的内置优化

模式名称模式名字特点场景
开发模式development调试代码、实时加载、模块热替换等本地开发
生产模式production压缩代码、资源优化、更轻量等打包上线

设置方式

  1. 在 webpack.config.js 配置文件设置 mode 选项
  2. 在 package.json 命令行设置 mode 参数
module.exports = {
    mode: 'development/production'
}
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode=production",
    "dev": "webpack serve --open --mode=development"
  },

命令行设置的优先级高于配置文件,推荐命令行设置。

打包模式的应用

在开发模式下用 style-loader 内嵌更快,生产模式下提取 css

方法1

webpack.config.js 配置导出函数,局限性大(只接受两种模式)

方法2

借助 cross-env (跨平台通用)包命令,设置参数区分环境

  • 下载 cross-env 软件包到当前项目
  • 配置自定义命令,传入参数名和值(会绑定到 proccess.env 对象下)
  • webpack.config.js 区分不同环境使用不同配置

下载:

npm i cross-env --save-dev

在 package.json 中配置自定义命令

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "cross-env NODE_ENV=production webpack --mode=production",
    "dev": "cross-env NODE_ENV=development webpack serve --open --mode=development"
  },

在 webpack.config.js 中区分不同环境使用不同配置

module: {
    rules: [
      {
        test: /\.css$/i,
        use: [ 
          process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader,
           "css-loader",
          ],//从后往前运行
      },
      {
        test: /\.less$/i,
        use: [ 
          process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader,
           "css-loader",
           "less-loader"
          ],//从后往前运行
      },
    ]
}
方法三

前端-注入环境变量

使用 webpack 内置的 DefinePlugin 插件

在编译时,将前端代码中匹配的变量名,替换为值或表达式

const webpack = require('webpack')
moudle.exports = {
  plugins: [
    new HtmlWebpackPlugin({
    new webpack.DefinePlugin({
      'process.env.NODE_ENV' : JSON.stringify( process.env.NODE_ENV )
    })
  ],
}

js 文件中使用

if (process.env.NODE_ENV === 'production') {
    console.log = function() {}
}
console.log('开发模式下好用,生产模式下失效')

五、开发环境调错 - source map

代码被压缩混淆,无法正确定位源代码位置(行数和列数)

source map:可以准确追踪 error 和 waring 在原始代码的位置

设置:

webpack.config.js 配置 devtool 选项

module.exports = {
	devtool: 'inline-source-map'
}

inline-source-map : 原始代码的信息一起打包在 js 文件内

仅在开发环境中使用,不在生产环境使用,防止被轻易查看源码位置

六、解析别名 alias

配置模块如何解析,创建 import 引入路径别名,来确保模块引入变得更简单

在 webpack.config.js 中配置解析别名 @ 来代表 src 绝对路径

const config = {
	//...
	resolve: {
		alias: {
			'@' : path.resolve(__diename, 'src')
		}
	}
}

module.exports = config

七、优化

CDN 的使用

CDN 内容分发网络,指的是一组分布在各个地区的服务器集合

把静态资源/第三方库放在 CDN 网络中各个服务器上,供用户就近访问

好处:

减轻自己服务器的请求压力,就近请求物理延迟低,配套缓存策略

开发模式使用本地第三方库,生产模式使用 CDN 加载引入

在 html 中引用第三方库的 CDN 地址并用模板语法判断
<head>
    //根据开发模式决定是否采用 cdn
    <% if(htmlWebpackPlugin.options.useCdn) {%>
    <link href="https://cdn.bootcdn.net/xxx/xxx.css" rel="stylesheet">
    <% } %>
</head>
//根据开发模式决定是否采用 cdn
<% if(WebpackHttp) {%>
<script src="https://cdn.bootcdn.net/xxx/xxx/xxx/xxx.css"></script>
<% } %>

配置 webpack.config.jsexternals 外部扩展选项(防止某些 import 的包被打包)

const config = {
    plugins: [
    new HtmlWebpackPlugin({
    //模板文件
    template: path.resolve(__dirname, 'public/login.html'),
    //输出文件
    filename: path.resolve(__dirname, 'dist/login/index.html'),
    //自定义的属性
    useCdn: process.env.NODE_ENV === 'production' //生产模式下使用 cdn 引入
    }),
    ],
}
    
//生产环境下使用相关的配置
if (process.env.NODE_ENV === 'production') {
  //外部扩展 防止打包
  config.externals = {
    //key: import from 语句后面的字符串
    //value:留在原地的全局变量(最好和 cdn 在全局暴露的变量一致)
    'bootstrap/dist/css/bootstrap.min.css': 'bootstrap',
    'axios' : 'axios'
  }
}
module.exports = config

分割公共代码

将公共代码提取

  • 配置 webpack.config.jssplitChunks 分割功能
splitChunks: {
    chunks: 'all',//所有模块动态非动态移入的都分割分析
    cacheGroups: {//分隔组
      commons: {//抽取公共模块
        minSize: 0,//抽取的chunk的最小大小
        minChunks: 2,//最小引用数
        reuseExistingChunk: true,//当前 chunk 包含已从主 bundle 中拆分的模块,则它将被重用
        name(module, chunks, cacheGroupKey) {//分离出模块文件名
            const allChunksNames = chunks.map((item) => item.name).join('~')//模块名1~模块名2
            return `./js/${allChunksNames}`//输出到 dist 目录下位置
        }
      }
    }
 }

八、多页面打包

单页面:单个 html 文件,切换 DOM 的方式实现不同业务逻辑展示

多页面:多个 html 文件,切换页面实现不同业务逻辑展示

添加多页面打包入口

entry: 
  {
    'login': path.resolve(__dirname, 'src/login/index.js'),
    'content': path.resolve(__dirname, 'src/content/index.js'),
    'publish': path.resolve(__dirname, 'src/publish/index.js')
  },

出口使用占位符动态生成

output: {
    path: path.resolve(__dirname, 'dist'),
    filename: './[name]/index.js',
    clean: true //生成打包内容之前,清空输出目录
  }

依据不同模块进行 html 打包

//导入 webpack 内置模块
const { Chunk } = require('webpack');

plugins: [
    new HtmlWebpackPlugin({
        //模板文件
        template: path.resolve(__dirname, 'public/login.html'),
        //输出文件
        filename: path.resolve(__dirname, 'dist/login/index.html'),
        useCdn: process.env.NODE_ENV === 'production', //生产模式下使用 cdn 引入
        chunks: ['login'], //引入 login 模块 (和 entry 的 key 一致)
    }),
    new HtmlWebpackPlugin({
        //模板文件
        template: path.resolve(__dirname, 'public/content.html'),
        //输出文件
        filename: path.resolve(__dirname, 'dist/content/index.html'),
        useCdn: process.env.NODE_ENV === 'production', //生产模式下使用 cdn 引入
        chunks: ['content'], //引入 content 模块 (和 entry 的 key 一致)
    }),
    new HtmlWebpackPlugin({
        //模板文件
        template: path.resolve(__dirname, 'public/publish.html'),
        //输出文件
        filename: path.resolve(__dirname, 'dist/publish/index.html'),
        useCdn: process.env.NODE_ENV === 'production', //生产模式下使用 cdn 引入
        chunks: ['publish'], //引入 content 模块 (和 entry 的 key 一致)
    }),
]

生产环境取消打包的外部扩展

//生产环境下使用相关的配置
if (process.env.NODE_ENV === 'production') {
  //外部扩展 防止打包
  config.externals = {
    //key: import from 语句后面的字符串
    //value:留在原地的全局变量(最好和 cdn 在全局暴露的变量一致)
    'bootstrap/dist/css/bootstrap.min.css': 'bootstrap',
    'axios' : 'axios',
    'form-serialize' : 'serialize',
    '@wangeditor/editor' : 'wangEditor'
  }
}

public/publish.html’),
//输出文件
filename: path.resolve(__dirname, ‘dist/publish/index.html’),
useCdn: process.env.NODE_ENV === ‘production’, //生产模式下使用 cdn 引入
chunks: [‘publish’], //引入 content 模块 (和 entry 的 key 一致)
}),
]


### 生产环境取消打包的外部扩展

//生产环境下使用相关的配置
if (process.env.NODE_ENV === ‘production’) {
//外部扩展 防止打包
config.externals = {
//key: import from 语句后面的字符串
//value:留在原地的全局变量(最好和 cdn 在全局暴露的变量一致)
‘bootstrap/dist/css/bootstrap.min.css’: ‘bootstrap’,
‘axios’ : ‘axios’,
‘form-serialize’ : ‘serialize’,
‘@wangeditor/editor’ : ‘wangEditor’
}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端mz小詹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值