工程化 --- webpack

1. 简述

webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当webpack 处理应用程序时,会在内部从一个或多个入口点构建一个 依赖图 ,然后将项目中所需的每一个模块组合成一个或多个bundles,它们均为静态资源,用于展示你的内容

**静态模块: ** 指的是编写代码过程中的 html、css、js、图片等固定内容的文件

**打包: ** 把静态模块内容 压缩、整合、转译等(前端工程化)

2. 中文文档

https://www.webpackjs.com/concepts/entry-points/

3. 环境搭建

1. 安装

npm i webpack webpack-cli --save-dev   # --save-dev  用来标记前面的这两个包只在当前项目的 dev 开发环境中使用

2. 配置自定义命令

package.json

{
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
        # 配置自定义命令
        "build": "webpack"
    }
}

3. 运行自定义命令

会将代码打包整合到项目根目录下的 dist 文件夹中

# 真正执行的命令就是上面配置的 webpack
npm run build

4. 常用配置

1. 准备配置文件

在项目根目录下创建 wepack.config.js

2. 入口

const path = require('path')

module.exports = {
  // 配置入口文件
  entry: path.resolve(__dirname,'src/login/index.js'),
};

3. 出口

const path = require('path')

module.exports = {
  entry: path.resolve(__dirname,'src/login/index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: './login/index.js',
    clean: true  // 生成打包后的内容前,先清空文件夹( 5.20.0 以上才能使用)
  },
};

5. 打包HTML

webpack默认只能识别js代码或json格式,HtmlWebpackPlugin 插件可以让webpack拥有识别html代码并自动生成 html 文件的能力

1. 安装

npm install --save-dev html-webpack-plugin

2. 配置

const HtmlWebpackPlugin = require('html-webpack-plugin')  // 导入插件
const path = require('path')

module.exports = {
  entry: path.resolve(__dirname,'src/login/index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: './login/index.js',
    clean: true
  },
  plugins: [
    new HtmlWebpackPlugin({  // 配置插件
      filename: path.resolve(__dirname,'public/login.html'), // 以自己的网页为基础生成模版
      template: path.resolve(__dirname,'dist/login/index.html')  // 生成后的模版的输出路径
    })
  ]
  ]
};

6. 打包 CSS 文件

6.1 css保存在js文件中

1.安装

css-loader

webpack默认只能识别js代码,css-loader 加载器可以让webpack拥有解析css代码的能力

style-loader

webpack默认只能识别js代码,style-loader 加载器可以让webpack拥有将解析后的 css代码 插入到 DOM 中的能力

npm i --save-dev css-loader
npm i --save-dev style-loader

2. 准备工作

1. 在js 文件中需要手动引入css文件

import './index.css'

3.配置

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
};

打包后的 css 会默认打包到 js 文件中,下面可以将css提取到单独的文件中,使浏览器并行的下载文件,提高页面加载速度

6.2 单独提取 css

css-loader 加载器 + mini-css-extract-plugin 插件

1. 安装

npm i --save-dev css-loader
npm i --save-dev mini-css-extract-plugin
npm i --save-dev css-minimizer-webpack-plugin 

2. 准备工作

1. 在js 文件中需要手动引入css文件

import './index.css'

3. 配置

webpack.config.js

const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
  plugins: [new MiniCssExtractPlugin({
          filename: "./login/index.css"   // 文件保存目标位置
      })],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
  optimization: {
    minimizer: [
      `...`, // webpack5 会根据这个配置压缩 js
      new CssMinimizerPlugin(), // 压缩 css
    ],
  },
};

7. 打包 less

7.1 安装

npm i --save-dev css-loader
npm i --save-dev less less-loader 

7.2 配置

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/i,
        use: [
          'style-loader',  // 这里可以选择使用 MiniCssExtractPlugin.loader 打包到独立的css文件
          'css-loader',
          'less-loader',
        ],
      },
    ],
  },
};

8. 打包图片

8.1 版本差异

在 webpack 5 之前,通常使用:

资源模块类型(asset module type),通过添加 4 种模式,来替换所有这些 loader:

  • asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
  • asset/inline 导出一个资源的 data URI(base64字符串)。之前通过使用 url-loader 实现。
  • asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
  • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择,如果资源大于8kb则使用 asset/resource 模式,小于则使用 asset/inline 模式。之前通过使用 url-loader,并且配置资源体积限制实现。

8.2 准备工作

1. 在js 文件中如果是本地图片资源需要手动引入图片文件,如果是网络图片,可以直接写

import imgObj from  './assets/logo.png'

8.3 配置

webpack.config.js

自定义输出到指定目录,方式一

const path = require('path');

module.exports = {
  output: {
    // ...
    assetModuleFilename: 'assets/[hash][ext][query]'
  },
  module: {
    rules: [
      {
       test: /\.(png|jpg|jpeg|gif)$/i,
       type: 'asset',
      }
    ]
  },
};

自定义输出到指定目录,方式二

webpack.config.js

const path = require('path');

module.exports = {
  output: {
    // ...
    assetModuleFilename: 'images/[hash][ext][query]'
  },
  module: {
    rules: [
      {
       test: /\.(png|jpg|jpeg|gif)$/i,
       type: 'asset',
       generator:{
           filename: 'assets/[hash][ext][query]'
       }
      }
    ]
  },
};

9. 搭建开发环境

借助了http模块创建了一个8080端口的web服务,默认以 webpack 配置的入口和出口 目录为服务器根目录,并且根据相关配置,打包相关代码在内存中,以output.path的值作为服务器根目录(所以可以直接自己拼接访问dist目录下的内容)

9.1 安装模块

npm i --save-dev webpack-dev-server

9.2 配置

package.json

{
   "scripts": {
     "dev": "webpack serve --open",  // --open 表示自动打开默认浏览器
   },
 }

webpack.config.js

const path = require('path');
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
  mode: 'development',  // 设置开发环境 
   entry: {
     index: './src/index.js',
     print: './src/print.js',
   },
   plugins: [
     new HtmlWebpackPlugin({
      title: 'Output Management',
      title: 'Development',
     }),
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
     clean: true,
   },
 };

9.3 生产模式和开发模式的内置优化

开发模式: development 调试代码,实时加载,模块热替换等特点

**生产模式: production **压缩代码,资源优化,更轻量等特点

**配置方式一: **

webpack.config.js

module.exports = {
    mode: 'production'
}

配置方式二: 优先级更高(推荐)

package.json

{
    "scripts": {
        "build": "webpack --mode=production"
        "dev": "webpack --mode=development"
    }
}

9.4 个性化配置

1. 需求

在开发模式下用 style-loader 将css 集成在js 文件中,生产模式下提取 css 代码到单独文件

1. 方案一

利用webpack.config,js 中配置导出函数,但是局限性大且只接收两种模式

module.exports = (env, argv) => {
  if (argv.mode === 'development') {
    config.devtool = 'source-map';
  }

  if (argv.mode === 'production') {
    //...
  }

  return config;
};

2. 方案二:

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

1. 安装

npm i --save-dev cross-env

2. 配置

package.json

{
    "scripts": {
        "build": "cross-env NODE_ENV=production webpack --mode=production",
        "dev": "cross-env NODE_ENV=development webpack server --open --mode=development"
    }
}

webpack.config.js

const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
  plugins: [new MiniCssExtractPlugin({
          filename: "./login/index.css"   // 文件保存目标位置
      })],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [process.env.NODE_ENV === 'development' ? "style-loader" : MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
  optimization: {
    minimizer: [
      `...`, // webpack5 会根据这个配置压缩 js
      new CssMinimizerPlugin(), // 压缩 css
    ],
  },
};

方案三: 配置不同的 webpack.config.js (适用于多种模式差异性较大的情况)

2. 需求

使用内置插件DefinePlugin,来实现在前端项目中,开发模式下打印函数生效,生产模式下打印函数失效

webpack.config.js

module.exports = {
  plugins: [new webpack.DefinePlugin({
      // key: 注入到打包后的前端js代码中作为全局变量
      // value: 变量对应的值(在cross-env 注入在node.js 中的环境变量字符串)
  	'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
	})],
};

前端代码中使用

if (process.env.NODE_ENV === "production") {
    console.log = function(){}   // 将console.log 赋值为一个空函数
}

request.js

// 配置 开发环境/ 生产环境 的 URL根地址
axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? 'http://192.168.0.89:8888' : 'http://www.baidu.com'

9.5 开发环境调错

webpack.config.js

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

// 确保该功能只在开发环境中生效
if (process.env.NODE_ENV === "develoment"){
    config.devtool = 'inline-source-map'
}
module.exports = config

9.6 路径别名 alias

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

webpack.config.js

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

module.exports = config

index.js

import {checkPhone} from '@/utils/check.js'

9.7 CDN 加速

**作用: ** 将 静态资源文件 / 第三方库 放在 CDN 网络中的各个服务器中,供用户就近请求获取

1. 需求

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

1. 在 html 中引入第三方库的 CDN 并用模版语法进行判断当前运行环境

<% if (htmlWebpackPlugin.options.useCdn)  %>
    <link href="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.11/dayjs.min.js" rel="stylesheet">
<% } %>

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

webpack.config.js

const config = {
    plugins: [new HtmlWebpackPlugin({
        useCdn: process.env.NODE_ENV === "production"
    })],
}

// 确保该功能只在开发环境中生效
if (process.env.NODE_ENV === "production"){
    config.externals = {
        // key: js代码导包时的 from 后面的标识字符串
        // value: js代码导包时的 import 后面的变量名(要与 cdn 暴露在全局的变量名一致)
        'dayjs': 'dayjs',
        "bootstrap/dist/css/bootstrap.min.css": "bootstrap"
    }
}
module.exports = config

10. 多页面打包

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

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

1. 准备源码.并改用模块化语法 导出 / 导入

2. 配置 webpack.config.js 的多入口和多页面设置

webpack.config.js

const config = {
    entry: {
        "模块名1": path.resolve(__dirname,'src/入口1.js'),
        "模块名2": path.resolve(__dirname,'src/入口2.js')
    },
    output: {
        path: path.resolve(__dirname,'dist'),
        filename: './[name]/index.js'
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './public/页面1.html',
            filename: './路径/index.html',
            chunks:["模块名1"]
        }),
        new HtmlWebpackPlugin({
            template: './public/页面2.html',
            filename: './路径/index.html',
            chunks:["模块名2"]
        })
    ]
}
module.exports = config

11. 提取公共代码

1. 配置

webpack.config.js

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

module.exports = config
posted @ 2024-06-13 10:23  河图s  阅读(12)  评论(0)    收藏  举报