webpack总结

62 阅读14分钟

webpack

1.什么是webpack

1.1 webpack

  • webpack 是一个现代的JavaScript 应用程序静态模块大包起(module bundler),他将许多文件是为一个整体,通过分析模块之间的依赖关系,最终将它们打包成一个或者多个静态资源文件,如:JavaScript,css,图片等
  • webpack 可以实现一下功能
    • 代码转换: 将ES6/TypeScript等高级语法语言转为浏览器可识别等第几语言
    • 文件优化:通过代码压缩,图片压缩,文件合并等方式来减小文件体积,加快页面加载速度
    • 模块合并:将多个模块合并成一个文件,减少HTTP请求数量
    • 依赖管理:通过分析模块之间的一览关系,自动加载所需的依赖模块
    • 插件扩展:通过插件扩展功能,满足不同项目的需求

1.2 webpack-cli

  • webpcak-cli 是wenpack官方提供的一个命令行工具,用与在终端中执行的webpack打包操作
  • webpack-cli 命令工具提供了多种指令,可以用于打包/编译/乘车配置文件/构建多页应用等

1.3安装

npm install webpack webpack-cli --save

2.webpack打包

2.1 entry

  • entry 选项用于指定webpack 打包的入口文件,即告诉webpack 从哪里文件开始打包
  • entry 可以配置成一个字符串,一个数组或者一个对象
    • entry 为一个字符串,表示是一个单独文件,webpack将该文件作为入口打包所有依赖的模块
    • entry为一个数组,表示入口文件有多个,wenpack将以数组中的文件作为入口打包所有的依赖模块
    • entry为一个对象,表示入口文件有多个且需要命名,wenbpack将根据对象中的见面生成多个入口文件
//webpack.config.js
	module.exprots = {
    mode:'developement',
    devtool:false,
    entry:'./src/index.js',
    /*
    entry:['./src/entry1.js','./src/entry2.js']
    entry:{
    	app:',.src/index,js'
    }
    */
  }

//package.json

{
  "scripts":{
    "build":"webpack"
  }
}

###2.2 output

  • output 选项用于指定webpack打包后输出的文件和路径,即告诉webpack打包之后的文件应该放在哪个目录及如何命名
  • output通常配置为一个对象,包含多个属性
    • path 指定了打包文件的输出路径,必须是一个绝对路径
    • filename 指定打包后的文件名称,可以包含路径信息
//webpack.config.js
const path = require('path')
module.exports = {
  mode:'development',
  devtool:'false',
  entry:'./src/index.js',
  output:{
    path:path.resolve(__dirame,'dist'),
    filname:'main.js'
  }
}

2.3 loader

  • wenpack中的Loader(加载器)用于对模块进行转换
  • wenpack 将一切文件视为模块,但是只有js模块才能被直接运行和使用
  • Loader可以将非JS模块转换为文本pack可以处理的有效模块

src.index,js

import './index.css'
console.log('index')

src\index.css

body {
	color:red;
}

webpack.config.js

  • 使用Loader需要在webpack配置文件中定义Loader规则

  • 每个Loader规则有两部分组成:匹配条件和处理方式

    • 匹配条件通常使用正则表达式,用匹配需要被转换的文件
    • 处理方式则是具体的转换操作
      • test:指定了匹配的文件类型
      • use:指定了转换方式
      • exclude 用于指定那些文件或者目录不应该被loader处理

    css-loader 作用是将css代码转为js代码,可以识别@import 和 url() 实现css模块的引用和解析

    style-loader 用于将css-loader转换后的js对象,以style标签的形式动态插入到HTML中

const path = require('path');
module.exports = {
  mode:'development',
  entry: './src/index.js',
  output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'main.js'
  },
 module: {
   rules: [
     { test: /\.css$/, use: ['style-loader','css-loader']}
   ]
 }
};

2.4 插件

  • 插件是一种用扩展webpack功能的机制,通过插件可以在webpack打包过程中执行的额外的任务或进行优化
    • html-webpack-plugin是wenpack中用于生产HTML文件的插件,可以根据模版生产HTML文件,饼子的将打包后的js/css文件引入HTML文件中
      • title 指定了HTML文件的标题
      • template指定了HTML文件的模版路径,及时用该模块生产HTML文件
const path = require('path');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode:'development',
  entry: './src/index.js',
  output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'main.js'
  },
  module: {
    rules: [
      { test: /\.css$/, use: ['style-loader','css-loader']}
    ]
  },
+ plugins: [
+   new HtmlWebpackPlugin({template: './src/index.html'})
+ ]
};

src\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>webpack</title>
</head>
<body>
</body>
</html>

2.5 webpack-dev-server

  • webpack-dev-server是一个基于 ExpressWeb 服务器,它可以为 Webpack 打包后的代码提供一个本地开发环境,支持实时刷新、热替换和自动构建等功能,大大提高了开发效率
    • static:静态资源目录的路径,设置该参数可以在服务器中访问这些静态资源
    • compress:启用 gzip 压缩,默认是关闭的
    • port:服务器端口,默认是 8080
    • host:服务器主机名,默认是 localhost
    • open:是否自动在浏览器中打开页面,默认是关闭的
    • hot:启用模块热替换功能,默认是关闭的
    • watchFiles:需要监听的文件列表,当这些文件发生变化时,自动重启服务器
    • historyApiFallback:参数用于设置是否启用 HTML5 历史记录 API,用于处理单页应用的路由问题。默认情况下,当使用浏览器的前进/后退按钮时,devServer 会尝试根据 URL 路径查找对应的静态资源,如果找不到就返回 404。如果启用了 historyApiFallback,则会将这些请求重定向到 index.html,然后交给前端路由来处理
  • 在命令行中运行 webpack-dev-server 命令后,webpack-dev-server 将会启动一个本地 Web 服务器,并监听我们定义的端口。我们可以在浏览器中访问 http://localhost:9000,即可预览打包后的页面,并实现实时刷新和热替换功能

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode:'development',
  entry: './src/index.js',
  output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'main.js'
  },
+ devServer: {
+   static: path.join(__dirname, 'public'),
+   compress: true,
+   host:'localhost',
+   port: 9000,
+   open:true,
+   hot:true,
+   historyApiFallback: true,
+   watchFiles: [
+     "src/**/*.js",
+     "src/**/*.css"
+   ]
+ },
  module: {
    rules: [
      { test: /\.css$/, use: ['style-loader','css-loader']}
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

package.json

{
  "scripts": {
    "build": "webpack",
+   "dev": "webpack serve"
  }
}

3. 处理CSS资源

  • css-loader 可以将 CSS 文件中的样式代码转换成 JavaScript 对象,并在 JavaScript 中导出,以便于其他 Loader 或插件进行处理。css-loader 支持使用 importurl() 等方式导入 CSS 文件和资源文件
  • style-loader 可以将 CSS 样式注入到 Webpack 打包后的 JavaScript 文件中,使得页面能够正确显示样式。它会将 CSS 样式代码插入到页面的 style 标签中,或以内联样式的方式插入到 head 标签中
  • mini-css-extract-plugin 当我们使用 style-loader 将 CSS 样式注入到 JavaScript 文件中时,每次页面加载都会将样式代码包含在 JavaScript 文件中,造成 JavaScript 文件变大,加载速度变慢,降低了页面的性能,为了解决这个问题,可以使用 mini-css-extract-plugin 插件,将 CSS 文件单独提取出来,生成独立的 CSS 文件,可以在页面加载时并行加载 CSS 文件,避免了 JavaScript 文件变大、加载缓慢的问题。此外,使用独立的 CSS 文件也可以让样式代码和 JavaScript 代码分离,方便维护和修改,提高开发效率

package.json

{
  "scripts": {
+   "build": "cross-env NODE_ENV=production  webpack",
+   "dev": "cross-env NODE_ENV=development  webpack serve"
  }
}

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  mode:'development',
  devtool:false,
  entry: './src/index.js',
  output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  module: {
    rules: [
      { test: /\.css$/, use: [
+       (process.env.NODE_ENV === 'development' ?
+         'style-loader' :
+         MiniCssExtractPlugin.loader)
        ,'css-loader']}
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'}),
+   new MiniCssExtractPlugin(),
  ]
};

4. 使用预处理器

  • less、sass、stylus 是一种基于 CSS 的扩展语言,它提供了更多的功能,比如变量、嵌套规则、运算、混合等等。Less 的代码可以转换为标准的 CSS 代码,从而可以在浏览器中直接使用
  • less-loader、sass-loader` 、Stylus-loader 是一个 Webpack 的 loader,它可以将 Less 代码转换为标准的 CSS 代码。在 Webpack 配置文件中,通过配置 Less-loader 可以让 Webpack 在构建项目时自动将 Less 代码转换为 CSS 代码

src\index.js

import './index.css';
+import './index.less';
console.log('index');

src\index.less

@color:red;
body{
    color: @color;
}

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  module: {
    rules: [
      {
        test: /\.css$/, use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
           'css-loader']
      },
+     {
+       test: /\.less$/, use: [
+         (process.env.NODE_ENV === 'development' ?
+           'style-loader' :
+           MiniCssExtractPlugin.loader),
+         'css-loader',
+         'less-loader'
+       ]
+     }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
  ]
};

5. PostCSS

  • PostCSS 是一个使用 JavaScript 插件转换 CSS 的工具。它可以帮助我们自动处理浏览器前缀、使用未来的 CSS 语法等问题
  • PostCSS 将 CSS 解析成 AST(抽象语法树),然后使用插件对 AST 进行处理,最后将处理后的 AST 转换为 CSS 代码
    • autoprefixer 是 PostCSS 的一个插件,它可以根据指定的浏览器版本自动添加所需的浏览器前缀。通过使用 autoprefixer,我们可以避免手动添加浏览器前缀的麻烦,同时也可以确保项目在各个浏览器中正确地显示
    • postcss-preset-env 是 PostCSS 的一个插件集合,它可以让我们使用未来的 CSS 语法,而不需要等待浏览器支持。postcss-preset-env 包含了一些常用的 CSS 预处理器的语法,如 Sass 和 Less,以及一些未来的 CSS 语法,如 CSS Grid、CSS Variables 等
    • postcss-less 是 PostCSS 的一个插件,它可以让我们使用 Less 预处理器的语法,从而可以更方便地编写 CSS 代码。通过使用 postcss-less,我们可以在 Webpack 构建项目时自动将 Less 代码转换为标准的 CSS 代码
    • stylelint 是一个强大的 CSS 校验工具,它可以帮助我们检查 CSS 代码是否符合一定的规范和最佳实践
  • browserslistrc 是一个文件,它用于指定当前项目需要支持的浏览器范围
    • last 2 versions:表示需要支持最近两个版本的所有浏览器
    • > 1%:表示需要支持全球使用率超过 1% 的浏览器
    • iOS 7:表示需要支持 iOS 7 版本的 Safari 浏览器
    • last 3 iOS versions:表示需要支持最近三个版本的 iOS Safari 浏览器

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  module: {
    rules: [
      {
        test: /\.css$/, 
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
            'css-loader',
+           "postcss-loader"
          ]
      },
      {
        test: /\.less$/, 
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
          'css-loader',
+         "postcss-loader",
          'less-loader'
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
  ]
};

postcss.config.js

module.exports = {
    plugins: [
        require("autoprefixer")
    ]
};

.browserslistrc

# Browsers that we support

last 2 versions
> 1%
iOS 7
last 3 iOS versions

6. Babel

  • ECMAScript6.0是 JavaScript 的一种标准化规范,ES6 引入了许多新特性,为 JavaScript 开发带来了巨大的改善和进步
  • Babel 是一个开源 JavaScript 转编译器,它能将高版本如 ES6 代码等价转译为向后兼容,能直接在旧版 JavaScript 引擎运行的低版本代码
    • @babel/preset-env是 Babel 的一个预设,用于自动检测目标环境并根据需要转换 JavaScript 代码
    • @babel/preset-env 会根据配置的目标环境,自动检测当前代码中使用的 ECMAScript 特性,并通过转换、降级或添加 polyfill 来保证代码在目标环境中能够正常运行
    • @babel/preset-env 的配置非常灵活,可以通过 .babelrcbabel.config.js、Webpack配置等多种方式来指定需要支持的目标环境
    • babel-preset-react是 Babel 的一个规则集,包含了常用的React插件,例如支持 preset-flowsyntax-jsxtransform-react-jsx 等插件
    • @babel/preset-typescript 是 Babel 的一个规则集,用于将 TypeScript 代码转译为 JavaScript 代码
    • @babel/preset-flow 是 Babel 的一个规则集,用于将 Flow 代码转译为 JavaScript 代码

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
+           loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.css$/, use: 
          [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
            'css-loader',
            "postcss-loader"
          ]
      },
      {
        test: /\.less$/, 
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
          'css-loader',
          "postcss-loader",
          'less-loader'
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
  ]
};

.babelrc

{
    "presets": [
      [
        "@babel/preset-env",
        {
          "targets": {
            "ie": "11"
          }
        }
      ]
    ]
  }

src\index.js

let sum = (a,b)=>a+b;
console.log(sum(1,2));

7. TypeScript

  • TypeScript 是一种由微软开发的开源编程语言,它是 JavaScript 的超集,扩展了 JavaScript 的语法和功能,提供了类型检查和面向对象编程等特性
    • resolve.extensions 是 Webpack 配置中的一个选项,用于配置在导入模块时可以省略的后缀名,在模块导入时,Webpack会按照指定的后缀名顺序依次尝试加载文件,直到找到匹配的文件为止

7.1 ts-loader

  • ts-loader 是 Webpack 中的一个加载器,用于将 TypeScript 代码转换成 JavaScript 代码。它是基于 typescript 编译器实现的,支持所有 TypeScript 的语法和特性,可以帮助开发者在 Webpack 中使用 TypeScript 进行开发

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  mode: 'development',
  devtool: false,
+ entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
+ resolve: {
+   extensions: ['.ts', '.js'],
+ },
  module: {
    rules: [
+     {
+       test: /\.ts$/,
+       use: 'ts-loader',
+       exclude: /node_modules/
+     },
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.css$/, use: 
          [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
            'css-loader',
            "postcss-loader"
          ]
      },
      {
        test: /\.less$/, 
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
          'css-loader',
          "postcss-loader",
          'less-loader'
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
  ]
};

tsconfig.json

{
    "compilerOptions": {
      "noImplicitAny": true,
      "moduleResolution": "node"
    }
  }

src\index.ts

const num:number = 0

7.2 babel-loader

  • @babel/preset-typescript 是 Babel 的一个预设,用于将 TypeScript 代码转换为 JavaScript 代码

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 
+       [
+         {
+           loader: 'babel-loader',
+           options: {
+             presets: ['@babel/preset-typescript']
+           }
+         }
+       ],
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.css$/, use: 
          [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
            'css-loader',
            "postcss-loader"
          ]
      },
      {
        test: /\.less$/, 
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
          'css-loader',
          "postcss-loader",
          'less-loader'
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
  ]
};

8. ESLint

  • ESLint是一个流行的JavaScript代码检查工具,旨在帮助前端开发者在编写代码时自动检查代码风格和语法错误。为了满足不同团队和项目的代码规范需求,ESLint生态中出现了许多基于不同代码规范的规则集合和插件
    • eslint-config-airbnb 是Airbnb提供的代码风格规则集,它是ESLint生态第一个成名的规则集合之一。它的优点在于提供了一套完整的、可自定义的代码规范,旨在帮助开发者编写具有一致性和可读性的代码
    • eslint-config-standard遵循Standard.js代码风格规范,提供了最便捷的统一代码风格的方式。使用该规则集可以避免因代码风格不一致而引起的错误和混乱
    • eslint-plugin-vueeslint-plugin-react插件来实现对SFC文件和React代码风格的检查
    • 针对TypeScript代码的检查,可以使用@typescript-eslint/eslint-plugin插件来检查代码风格和语法错误
    • eslint-plugin-sonarjs插件,该插件基于Sonar提供了代码质量检查工具,提供圈复杂度、代码重复率等检测功能

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+const ESLintPlugin = require('eslint-webpack-plugin')
module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 
        [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-typescript']
            }
          }
        ],
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.css$/, use: 
          [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
            'css-loader',
            "postcss-loader"
          ]
      },
      {
        test: /\.less$/, 
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
          'css-loader',
          "postcss-loader",
          'less-loader'
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
+   new ESLintPlugin({ extensions: ['.js', '.ts'] })
  ]
};

.eslintrc

{
    "parser": "@typescript-eslint/parser",
    "plugins": ["@typescript-eslint"],
    "extends": ["plugin:@typescript-eslint/recommended"]
}

src\index.ts

let sum = (a:number,b:number)=>a+b;
console.log(sum(1,2));

9.图像

9.1 asset-modules

  • module.rules.type`用于指定加载器的类型,也就是告诉Webpack该如何处理不同类型的文件
  • asset-modules
  • 在默认情况下,使用asset/resource类型的加载器会生成带有[hash][ext][query]后缀的文件名。如果需要自定义文件名,可以通过设置output.assetModuleFilename属性进行控制
  • module.rules.parser.dataUrlCondition用于限制文件大小的阈值
  • Asset Modules类型通过添加 4 种新的模块类型替代了所有这些加载器
    • asset/resource 生成单独的文件并导出 URL
    • asset/inline 导出资产的数据 URI
    • asset/source 导出资产的源代码
    • asset 会自动选择导出数据 URI 还是生成单独的文件,可以设置文件大小限制来实现

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const ESLintPlugin = require('eslint-webpack-plugin')
module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use:
          [
            {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-typescript']
              }
            }
          ],
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.css$/, use:
          [
            (process.env.NODE_ENV === 'development' ?
              'style-loader' :
              MiniCssExtractPlugin.loader),
            'css-loader',
            "postcss-loader"
          ]
      },
      {
        test: /\.less$/,
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
          'css-loader',
          "postcss-loader",
          'less-loader'
        ]
      },
+     {
+       test: /\.(png)$/,
+       type: 'asset/resource'
+     },
+     {
+       test: /\.(jpg)$/,
+       type: "asset/inline"
+     },
+     {
+       test: /\.(bmp)$/,
+       type: "asset",
+       parser: {
+         dataUrlCondition: {
+           maxSize: 1024
+         }
+       }
+     },
      {
        test: /\.svg$/i,
       type: "asset/source"
      },
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
    new ESLintPlugin({ extensions: ['.js', '.ts'] })
  ]
};

9.2 压缩图片

  • image-webpack-loader可以在Webpack打包过程中对图片进行优化和压缩,从而减小图片文件的大小,提高页面加载速度和响应速度
  • 它的底层依赖于imagemin和一系列的图像优化工具,包括mozjpegoptipngpngquantsvgogifsiclewebp等,可以自动选择最优的优化工具对图片进行处理
    • optipng:用于压缩PNG图片的配置项
    • pngquant:同样用于压缩PNG图片的配置项,可以设置图片质量和压缩速度
    • svgo:用于压缩SVG图片的配置项,包含多个插件
    • gifsicle:用于压缩Gif图片的配置项
    • webp:用于将JPG/PNG图片压缩并转换为WebP图片格式的配置项
npm install image-webpack-loader --save

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const ESLintPlugin = require('eslint-webpack-plugin')
module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use:
          [
            {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-typescript']
              }
            }
          ],
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.css$/, use:
          [
            (process.env.NODE_ENV === 'development' ?
              'style-loader' :
              MiniCssExtractPlugin.loader),
            'css-loader',
            "postcss-loader"
          ]
      },
      {
        test: /\.less$/,
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
          'css-loader',
          "postcss-loader",
          'less-loader'
        ]
      },
      {
        test: /\.(png)$/,
        type: 'asset/resource'
      },
      {
        test: /\.(jpg)$/,
        type: "asset/inline"
      },
      {
        test: /\.(bmp)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 1024
          }
        }
      },
      {
        test: /\.svg$/i,
       type: "asset/source"
      },
+     {
+       // 匹配文件的正则表达式,这里表示匹配JPG、PNG、GIF和SVG格式的图片文件
+       test: /\.(jpe?g|png|gif|svg)$/i, 
+       use: [
+         {
+            // 使用image-webpack-loader对图片进行优化和压缩
+           loader: 'image-webpack-loader',
+           options: {
+             // 是否禁用图片优化和压缩
+             disable: process.env.NODE_ENV === 'development', 
+             mozjpeg: {
+               progressive: true, // 是否开启渐进式JPEG,可以有效提升JPEG图片加载速度
+               quality: 65 // 压缩JPEG图片的质量,取值范围为0到100,值越大质量越好但文件越大
+             },
+             optipng: {
+               enabled: true // 是否开启PNG图片的优化,可以有效提升PNG图片加载速度
+             },
+             pngquant: {
+               // 压缩PNG图片的质量范围,取值范围为0到1,值越大质量越好但文件越大
+               // 第一个数字表示压缩质量的下限,第二个数字表示压缩质量的上限
+               quality: [0.65, 0.9], 
+               speed: 4 // 压缩PNG图片的速度,取值范围为1到10,值越大速度越快但质量越低
+             },
+             svgo: {
+               plugins: [ // 压缩SVG图片的插件列表,这里包含removeViewBox和cleanupIDs两个插件
+                 { //用于删除SVG图片中的viewBox属性
+                   //viewBox属性是用来指定SVG视口范围的,它的值是一个矩形框的坐标和宽高
+                   removeViewBox: false
+                 },
+                 { //用于删除SVG图片中的无用ID属性
+                   cleanupIDs: true
+                 }
+               ]
+             },
+             gifsicle: {
+               interlaced: true // 是否开启GIF图片的隔行扫描,可以有效提升GIF图片加载速度
+             }
+           }
+         }
+       ]
+     }      
   ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
    //new ESLintPlugin({ extensions: ['.js', '.ts'] })
  ]
};

9.3 响应式图片

  • 响应式图片是指能够根据设备屏幕大小和分辨率等因素动态调整显示大小和清晰度的图片

  • 在不同设备上显示同一张图片时,响应式图片可以自动选择最优的图片版本,从而保证图片显示效果的一致性和优化网站性能

  • responsive-loader
    

    是一个webpack的loader,用于实现响应式图片的功能。它可以根据设备屏幕大小和像素密度等因素自动调整图片大小和清晰度,从而提高网站的用户体验和性能

    • sizes:用于指定不同尺寸的图片大小。在这个例子中,我们指定了4个不同的图片大小,分别是300px、600px、1200px和2000px。当加载图片时,responsive-loader会根据设备的屏幕大小和像素密度等因素自动选择最合适的图片大小
    • adapter:用于指定图片处理库。在这个例子中,我们使用了sharp库,它是一个高性能的图片处理库,可以用来自动调整图片大小和清晰度
  • srcset和sizes是HTML中img标签的两个属性,用于实现响应式图片的功能,可以根据设备屏幕大小和像素密度等因素自动选择最合适的图片版本和显示大小,从而提高网站的用户体验和性能

  • srcset属性用于指定不同尺寸和清晰度的图片版本,它的值是一个以逗号分隔的图片列表,每个图片元素包含了图片URL和对应的宽度或像素密度等信息

  • sizes属性用于指定图片在不同屏幕尺寸下的显示大小,它的值是一个以逗号分隔的尺寸列表,每个尺寸元素包含了媒体查询和对应的尺寸信息

  • 浏览器加载这个img标签时,它会根据设备的屏幕大小和像素密度等因素,选择最合适的图片版本,并根据sizes属性指定的尺寸大小进行显示

npm i responsive-loader sharp --save

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const ESLintPlugin = require('eslint-webpack-plugin')
module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use:
          [
            {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-typescript']
              }
            }
          ],
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.css$/, use:
          [
            (process.env.NODE_ENV === 'development' ?
              'style-loader' :
              MiniCssExtractPlugin.loader),
            'css-loader',
            "postcss-loader"
          ]
      },
      {
        test: /\.less$/,
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
          'css-loader',
          "postcss-loader",
          'less-loader'
        ]
      },
/*       {
        test: /\.(png)$/,
        type: 'asset/resource'
      },
      {
        test: /\.(jpg)$/,
        type: "asset/inline"
      },
      {
        test: /\.(bmp)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 1024
          }
        }
      },
      {
        test: /\.svg$/i,
       type: "asset/source"
      },
      {
        // 匹配文件的正则表达式,这里表示匹配JPG、PNG、GIF和SVG格式的图片文件
        test: /\.(jpe?g|png|gif|svg)$/i, 
        use: [
          {
             // 使用image-webpack-loader对图片进行优化和压缩
            loader: 'image-webpack-loader',
            options: {
              // 是否禁用图片优化和压缩
              disable: process.env.NODE_ENV === 'development', 
              mozjpeg: {
                progressive: true, // 是否开启渐进式JPEG,可以有效提升JPEG图片加载速度
                quality: 65 // 压缩JPEG图片的质量,取值范围为0到100,值越大质量越好但文件越大
              },
              optipng: {
                enabled: true // 是否开启PNG图片的优化,可以有效提升PNG图片加载速度
              },
              pngquant: {
                // 压缩PNG图片的质量范围,取值范围为0到1,值越大质量越好但文件越大
                // 第一个数字表示压缩质量的下限,第二个数字表示压缩质量的上限
                quality: [0.65, 0.9], 
                speed: 4 // 压缩PNG图片的速度,取值范围为1到10,值越大速度越快但质量越低
              },
              svgo: {
                plugins: [ // 压缩SVG图片的插件列表,这里包含removeViewBox和cleanupIDs两个插件
                  { //用于删除SVG图片中的viewBox属性
                    //viewBox属性是用来指定SVG视口范围的,它的值是一个矩形框的坐标和宽高
                    removeViewBox: false
                  },
                  { //用于删除SVG图片中的无用ID属性
                    cleanupIDs: true
                  }
                ]
              },
              gifsicle: {
                interlaced: true // 是否开启GIF图片的隔行扫描,可以有效提升GIF图片加载速度
              }
            }
          }
        ]
      }, */
+     {
+                test: /\.(jpe?g|png)$/i,
+               //oneOf是一个优化选项,用于提高打包的速度
+               oneOf:[
+                   {
+                       //resourceQuery是一个用于匹配请求资源的URL中查询字符中
+                       resourceQuery:/sizes/,
+                       use:[
+                           {
+                            loader:'responsive-loader',
+                            options:{
+                               sizes:[300,600,1024],
+                               adapter:require('responsive-loader/sharp')
+                            }
+                           }
+                        ]
+                   },
+                   {
+                       type: 'asset/resource',
+                   }
+               ]
+           }   
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
    //new ESLintPlugin({ extensions: ['.js', '.ts'] })
  ]
};

src/index.js

import responsiveImg from './images/bg.png?sizes[]=300,sizes[]=600,sizes[]=1024';
console.log(bg);
let image = new Image();
image.srcset = responsiveImg.srcSet;
image.sizes = `(min-width: 1024) 1024px,100vw`;
document.body.appendChild(image);

9.4 雪碧图

  • 雪碧图(Sprite)是指将多个小图片(如图标、小按钮等)合并成一张大图片,通过CSS的background-position属性来控制显示不同的小图片。它的优点是减少HTTP请求次数,提高页面的加载速度和性能
  • webpack-spritesmith是一个webpack插件,用于生成雪碧图。它可以将多个小图片合并成一张大图片,并在生成的CSS文件中自动生成background-position属性和样式代码,简化了雪碧图的生成和使用过程
  • resourceQuery是一个用于匹配资源请求URL的查询字符串。它可以用于在webpack中对不同资源做不同的处理
  • oneOf是一个用于优化打包速度的属性。通常情况下,webpack会按照配置中的loader顺序依次尝试处理模块,直到找到能够处理该模块的loader,这个过程会花费一定的时间,影响打包速度。而使用oneOf可以让webpack只尝试一次匹配,并使用第一个匹配成功的loader来处理模块,从而提升打包速度

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const ESLintPlugin = require('eslint-webpack-plugin')
const SpritesmithPlugin = require('webpack-spritesmith');

module.exports = {
  mode: 'development',
  devtool: false,
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  devServer: {
    static: path.join(__dirname, 'public'),
    compress: true,
    port: 9000
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use:
          [
            {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-typescript']
              }
            }
          ],
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.css$/, use:
          [
            (process.env.NODE_ENV === 'development' ?
              'style-loader' :
              MiniCssExtractPlugin.loader),
            'css-loader',
            "postcss-loader"
          ]
      },
      {
        test: /\.less$/,
        use: [
          (process.env.NODE_ENV === 'development' ?
            'style-loader' :
            MiniCssExtractPlugin.loader),
          'css-loader',
          "postcss-loader",
+         {
+             loader:'less-loader',
+             options:{
+                 lessOptions:{
+                     paths:[
+                         path.resolve(__dirname,'src/spritesmith-generated')
+                     ]
+                 }
+             }
+         }
        ]
      },
      /*  {
        test: /\.(png)$/,
        type: 'asset/resource'
      },
      {
        test: /\.(jpg)$/,
        type: "asset/inline"
      }, */
      {
        test: /\.(bmp)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 1024
          }
        }
      },
      {
        test: /\.svg$/i,
        type: "asset/source"
      },
       {
        // 匹配文件的正则表达式,这里表示匹配JPG、PNG、GIF和SVG格式的图片文件
        test: /\.(jpe?g|png|gif|svg)$/i, 
        use: [
          {
             // 使用image-webpack-loader对图片进行优化和压缩
            loader: 'image-webpack-loader',
            options: {
              // 是否禁用图片优化和压缩
              disable: process.env.NODE_ENV === 'development', 
              mozjpeg: {
                progressive: true, // 是否开启渐进式JPEG,可以有效提升JPEG图片加载速度
                quality: 65 // 压缩JPEG图片的质量,取值范围为0到100,值越大质量越好但文件越大
              },
              optipng: {
                enabled: true // 是否开启PNG图片的优化,可以有效提升PNG图片加载速度
              },
              pngquant: {
                // 压缩PNG图片的质量范围,取值范围为0到1,值越大质量越好但文件越大
                // 第一个数字表示压缩质量的下限,第二个数字表示压缩质量的上限
                quality: [0.65, 0.9], 
                speed: 4 // 压缩PNG图片的速度,取值范围为1到10,值越大速度越快但质量越低
              },
              svgo: {
                plugins: [ // 压缩SVG图片的插件列表,这里包含removeViewBox和cleanupIDs两个插件
                  { //用于删除SVG图片中的viewBox属性
                    //viewBox属性是用来指定SVG视口范围的,它的值是一个矩形框的坐标和宽高
                    removeViewBox: false
                  },
                  { //用于删除SVG图片中的无用ID属性
                    cleanupIDs: true
                  }
                ]
              },
              gifsicle: {
                interlaced: true // 是否开启GIF图片的隔行扫描,可以有效提升GIF图片加载速度
              }
            }
          }
        ]
      },
     {
       test: /\.(jpe?g|png)$/i,
       oneOf:[
           {
             resourceQuery: /sizes?/,
             use: [
               {
                 loader: 'responsive-loader',
                 options: {
                   adapter: require('responsive-loader/sharp'),
                 },
               },
             ]
           },
           {
             type:'asset/resource',
           }
       ]
     },     
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './src/index.html' }),
    new MiniCssExtractPlugin(),
    //new ESLintPlugin({ extensions: ['.js', '.ts'] })
+   new WebpackSpritesmith({
+   src:{//指定输入的文件
+       cwd:path.resolve(__dirname,'src/images/icons'),
+       glob:'**/*.png'
+   },
+   target:{//指定输出的文件路径
+       image:path.resolve(__dirname,'src/spritesmith-generated/sprite.png'),
+       css:path.resolve(__dirname,'src/spritesmith-generated/sprite.less'),
+   },
+   apiOptions:{
+       cssImageRef: "sprite.png"
+   },
+   spritesmithOptions: {
+       algorithm: 'top-down',
+       padding: 10
+     }
+   })
  ]
};

src/index.js

import './icons.less'

src\icons.less

@import 'sprite.less';
.icon-twitter {
    .sprite(@twitter);
}
.icon-facebook  {
    .sprite(@facebook);
}
.icon-github  {
    .sprite(@github);
}