webpack 基础

Webpack:

配置文件:

var path = require('path')

module.exports = {
    entry: './a.js', // 要打包的入口文件
    output: {
        path: path.resolve(__dirname,''), // 输出路径
        filename: 'out.js' // 输出文件名称
    },
    mode: 'none' // 模式 默认 production 给生产环境打包,会压缩,none 不会
}

Webpack loader :

Loader 是 Webpack 生态的一个重要组成,一般称为预处理器

Webpack 在进行打包时,对所有引入的资源文件,都当做模块,但是它本身只支持对 js 文件处理(现支持 json),如果引入 css 或 图片文件,那么在处理该模块是会报错。

         `Module parse failed…You may need an appropriate loader to handle this file type.`            

此时 loader 就起作用了

css-loader 作用为 解析 css 文件 包括 @import 等 css 语法,作用也仅是解析 css 文件,在解析完成之后,以字符串形式将 css 插入 js 文件中,此时 css 并未生效,需要插入 html

style-loader 作用为将 js 中的 css 样式插入 html 中,原理很简单,即动态的生成 style 标签 插入 html 中的 head 标签中

// 配置

const path = require('path') // 导入 path 模块 为了获取文件路径

module.exports = { // 模块输出
    entry: './a.js', // 要打包的项目入口文件
    output: { // 输出信息
        path: path.resolve(__dirname,''), // 输出路径
        filename: 'bundle.js' // 输出文件名
    },
    module: { // 模块内容
        rules: [{
            test: /\.css$/ , // 正则匹配 css 文件
            use: ['style-loader','css-loader'] 
            // 使用 style-loader 和 css-loader 解析 css 文件 从后向前执行
        }]
    },
    mode: 'none' // 使用 none 模式 不压缩内容,否则默认压缩
}

Webpack 入口与出口:

Webpack 会将所有依赖的文件打包到一个 .js 文件中,但是这通常不是希望打包出来的资源,如果要拆分 js 、css 图片等资源的话,可以在构建的时候,通过预处理器 loader 和 插件 plugin 进行干预,将 .js 文件转换为 js、css 、图片资源

模块化 import 与 require 的区别:

Webpack 是模块打包工具,将一切文件视为模块,本身支持非常多的模块化方法。

import 有 impot '' 和 impot() 两种方法:

  • import '' 同步
  • import() 异步

Webpack 在打包时,碰到 import() 引入的模块不会立即将模块内容导入,而是会动态生成 js 即在运行时 生成 script 标签,import() 导入模块后是 promise 对象,可通过 impot().then() 处理后续异步工作

而 require 是 Commonjs 的内容

主要在 node.js 中使用,主要通过 module.exports 到处模块 ,require('') 导入模块


Webpack 入口 entry:

Webpack 配置内容:

var path = require('path')
module.exports = {
    entry: './index.js',
    output: {
        path: path.resolve(__dirname,''),
        filename: 'bundle.js'
    },
    mode: 'none'
}

上述配置为 根据当前目录的 index.js 打包 输出为 当前目录的 bundle.js

entry 就是 资源入口文件 ,是一个相对路径

Webpack 基础目录 context

上面配置省略了一个配置参数 context,Webpack 官方称之为 基础目录 (base directory)

context 在 Webpack 中表示 资源入口文件 entry 是从那个目录为起点的,context 值为字符串,表示绝对路径

var path = require('path')

module.exports = {
    context: path.resolve(__dirname,'./src'),
    entry: './js/a.js', 
    output: {
        path: path.resolve(__dirname,''),
        filename: 'bundle.js'
    },
    mode: 'none'
}

上述配置为 从工程根目录下 src 文件夹的 a.js 开始打包

一般不会设置 context ,不设置 context 时,它是当前工程根目录

Webpack 资源入口 entry

Webpack 资源入口 entry 代表路径为相对路径,可以是字符串、数组、对象、函数形式

  • 字符串形式:
    `entry: 'index.js'`

  • 数组形式:
    ` entry: ['core-js/stable','regenerator-runtime/runtime','./index.js']`
    表示数组最后一项为 资源入口文件 数组其余文件会预先构建到入口文件

 // 上面配置 与 下面配置 是等价的

 // index.js
 import 'core-js/stable'
 import 'regenerator-runtime/runtime'

 // webpack.config.js
 module.exports = {
     entry: './index.js'
 }
  • 对象形式:

    var path = require('path')
    
    module.exports = {
       entry: {
      entry: {
         app: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'],
         vendor: './vendor'
       },
       output: {
         path: path.resolve(__dirname, ''),
         filename: '[name].js'
       },
       mode: 'none'  
    };
    

    分别从两个入口文件打包,每个入口文件各自寻找自己依赖的文件模块打包成一个 js ,最终得到两个 js 文件

  • 函数形式:
    Webpack 取 函数返回值作为入口配置,返回值是以上三种之一即可
    函数形式的 entry 用于做逻辑处理,但少用


Webpack 出口 output

var path = require('path');  
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, ''),
      filename: 'bundle.js'
    },
    mode: 'none'
  };

output 就是 资源出口配置项,是一个对象,有属性 filename、path、publicPath、chunkFilename 等重要属性

  • Webpack 的 output.filename
    打包生成的资源名称,可根据需要修改,除文件名称外,
    也可使相对路径。最终的输出的是 path + filename 的拼接
    支持类似变量的方式动态生成文件名,如 `[hash]方括号表示特定的动态值 <br> 即 hash (哈希) 值,生成的文件名回事打包时的 hash 值 <br> 特定动态值除 ``[hash]` 外, 还有[name]`` ,表示的为 chunk 的名称,
    简单理解为,每一个资源入口,异步模块资源都 代表一个 chunk
    对于 字符串和数组形式的 entry `[name]值都为 main <br> 对于 entry 为对象形式的多入口配置,``[name]` 为属性名,对应入口文件 <br> 特定动态值还有[hash]、[chunkhash]、[contenthash]``
  • Webpack 的 output.path
    表示资源打包的输出位置,要是绝对路径,Webpack4 默认为 dist 目录
  • Webpack 的 output.publicPath
    表示资源访问路径,指的是 output 的,资源输出位置表示打包完成后,资源存放的磁盘位置
    浏览器通过 资源访问路径 访问资源
    表现形式有两个,相对路径 和 绝对路径
  • 相对路径,又分为两种情况
    • 相对于当前浏览的 html 页面路径取值 ,以 ./ 或 ../ 开头
    • 相对于当前页面的服务器地址路径取值 , 以 / 开头
  • 绝对路径,output.publicPath 以 HTTP 协议名称开始,一般在使用了 CDN 时使用
    因 CDN 域名与服务器域名会不一样,协议名称有 http 和 https ,或使用相对协议
    即 以 // 开头,省略前缀 https: 或 http:,
    使用相对协议时,浏览器会以当前页面使用协议与相对协议拼接
  • Webpack 的 output.chunkFilename
    chunkFilename 也是用于表示 打包生成的文件名
    与 filename 区别在于 表示的是在打包过程中 非入口文件的 chunk 名称
    通常在使用 异步模块时 会生成非入口文件的 chunk

hash 、chunkhash 、contenthash 区别:

当浏览器访问一个 html 页面时,html 页面会加载 js css 等外部资源,需要花费一定下载时间

如果页面上有一些外部资源是长期不变的,如 JQuery 或 商标图片等 可以将这部分资源存储在本地,这就是缓存

浏览器获得资源后,只有同名的资源在缓存有效期内,就会把该资源一直缓存在本地,于是下次访问之后,对于相同的资源,不会再请求服务器,而是直接用本地资源。

可在服务器上设置缓存有效期为几天,几月,几年,使得资源长期缓存在本地。

如果资源内容变化了,但是名称不变,那么浏览器不会重新下载资源,所以要给资源一个独特的命名,如

jquery-2df3ad34.js 这种,只要内容不变,名称不变,内容一变,名称也随之变,

于是浏览器找不到资源,就会重新请求服务器

而要保证类似 2df3ad34 这种名字是唯一的,就需要依靠 hash

在使用 Webpack 构建时,Webpack 会根据所有文件内容计算 hash,只要文件内容变动,就会重新计算

一般取 生成的 hash 前八位作文件名一部分

在 Webpack 中 通过以 `[hash:8]` 方式表示取 hash 值前八位

如: `filename: 'jquery-[hash:8].js'`

在 Webpack 中 hash 、 chunkhash 、 contenthash 都是根据文件内容计算 hash

hash 是根据打包中所有 文件 计算出的 hash,在一次打包中,所有出口文件的 filename 获得的 hash 都是一样的

chunkhash 是根据打包过程中当前 chunk 计算的 hash,如果为 Webpack 配置的是 多入口配置,通常会生成对个 chunk,每个 chunk 对应的 出口 filename 获得的 `[chunkhash]` 是不一样的

contenthash 类似 chunkhash,是根据 打包时 css 内容计算的 hash,一般使用提取 css 的插件使用


Webpack 预处理器 loader:

预处理器 loader 本质上是一个函数,接受资源模块,将其处理成 Webpack 核心能使用的形式

loader 配置:

  const path = require('path');
  module.exports = {
    entry: './a.js',  // a.js里引入了CSS文件
    output: {
      path: path.resolve(__dirname, ''),
      filename: 'bundle.js'
    },
    module: {
      rules: [{
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }]
    },
    mode: 'none'
  };

配置 loader 是在 Webpack 中的 module 配置项进行的,用 module 是因为这个配置项是解析和处理模块的。

module 的配置项中 最重要的一个 配置子项 就是 rules。它定义了 loader 的处理规则

rules 是一个数组,数组每一项都是 js 对象,对象有两个关键属性 test 和 use

test 是匹配模块文件名的正则 如 `/\.css$/` ,与正则匹配的模块会被 use 的 loader 处理

use 可以使 字符串 、对象 、数组,表示使用的 loader,如果是单一 loader 那么可以取字符串,

`use: 'babel-loader'`

如果有额外配置参数,取对象,参数放在 options(部分 loader 放 query)中

`use: {loader: 'babel-loader',options: {...}}`

如果使用多个 loader 进行链式处理,取数组,数组每一项都可以是 字符串或对象

除 test 、 use 外, rules 还有 exclude 、 include 、resource 、 issure 、 enforce 等参数

exclude 与 include

如果有文件不想被正则匹配的 loader 处理,可配置 exclude 项,exclude 中文意为排除

`exclude: /node_modules/`

而 include 与 exclude 相反,它表示只对匹配的文件处理

`include: /src/`

enforce

对同一类后缀名类型的文件,可使用多个 loader 处理,loader 处理顺序为 从后向前

如果想强制某个 loader 最先处理或最后处理,使用 enforce

Webpack 推荐的 enforce 项有两个,pre 和 post

pre 表示 在所有的 loader 之前执行

post 表示在 所有的 loader 之后执行

 rules: [{
    test: /\.js$/,
    use: ['eslint-loader'],
    enforce: 'pre',
    exclude: /node_modules/,
  }]
// 表示在 所有 处理 js 的 loader 之前执行 eslint-loader,进行代码规范检查校验
resource 和 issuer

resource 意为资源,issuer意为发行人

在 Webpack 中 被加载的模块称为 resource,实施加载的模块称为 issuer

而 test 和 exclude 是使用了默认 resource 的

 rules: [{
    test: /\.css$/,
    use: ['style-loader', 'css-loader'],
    exclude: /node_modules/
  }]

// 两个配置是等价的

rules: [{
    use: ['style-loader', 'css-loader'],
    resource: {
      test: /\.css$/,
      exclude: /node_modules/
    }
  }]

如果要指定只有 src 目录下引用的 css 可以被相应的 loader 处理,可配置 issuer

  rules: [{
    test: /\.css$/,
    use: ['style-loader', 'css-loader'],
    exclude: /node_modules/,
    issuer: {
      test: /\.js$/,
      include: /src/
    }
  }]

// 两个配置是等价的

  rules: [{
    use: ['style-loader', 'css-loader'],
    resource: {
      test: /\.css$/,
      exclude: /node_modules/
    },
    issuer: {
      test: /\.js$/,
      include: /src/
    }
  }]

babel-loader

主要用于在 Webpack 打包时,用 Babel 将 ES6 转换为 ES5

同时还有预设 `@babel/preset-env` ,如果不使用 babel-loader 那么依旧可以使用 Webpack 进行打包,但是打包后的 ES6 代码不会转换为 ES5

const path = require('path');
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, ''),
      filename: 'bundle.js'
    },
    module: {
      rules: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          }
        }
      ]
    },
    mode: 'none'
  };

除使用 babel-loader ,还增加了配置项 options ,该配置与 babel 配置文件基本一致,这里使用 @babel/preset-env

babel-loader 配置项 options 除了正常的 babel 配置文件配置项,还可以开启缓存,通过 `cacheDirrctory:true` 开启缓存,在初次打包后,如果再次打包,文件没有发生变化,可直接使用初次打包后的缓存文件。

babel 配置如果过于复杂,可单独建立配置文件,如 babel.config.js 。babel-loader 会自动读取使用默认 配置文件配置


file-loader

是一个通用文件处理 loader,在 Webpack 中作用为 处理文件导入地址并替换成其访问地址,并把文件输出到响应位置。

可以处理 js 通过 import 引入的图片

  // webpack.config.js
  const path = require('path');
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, ''),
      filename: 'bundle.js'
    },
    module: {
      rules: [{
        test: /\.jpg$/,
        use: 'file-loader'
      }]
    },
    mode: 'none'
  };

可以处理 css 导入的 图片

  // webpack.config.js
  const path = require('path');
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, ''),
      filename: 'bundle.js'
    },
    module: {
      rules: [{
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },{
        test: /\.jpg$/,
        use: 'file-loader'
      }]
    },
    mode: 'none'

url-loader

是 file-loader 的增强版,支持所有 file-loader 功能,还有一个特殊功能

即,可以计算出文件的 base64 编码,在文件体积小于指定值时(单位 byte )可以返回一个 base64 编码的 DataURL 代替访问地址

使用 base64 的好处就是可以减少一次网络请求,提升页面加载速度

 // webpack.config.js
  const path = require('path');
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, ''),
      filename: 'bundle.js'
    },
    module: {
      rules: [{
        test: /\.(jpg|png)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 1024 * 8, // 图片体积小于 8 kb 的转 base64 编码 URL 直接写入文件
          }
        }
      }]
    },
    mode: 'none'
  };

file-loader 生成文件默认名称为 `[contenthash].[ext],``[contenthash]` 是资源内容 hash 值,[ext]`` 是 文件扩展名

还有 hash 和 name,hash 是根据内容计算 hash,name 是 原始名称

file-loader 默认使用 output.publicPath 作资源访问路径,也可以在 file-loader 的配置项 options 中配置 publicPath 参数,它会覆盖 output.publicPath

// webpack.config.js
  const path = require('path');
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'bundle.js'
    },
    module: {
      rules: [{
        test: /\.(jpg|png)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 1024 * 8,
            name: '[name]-[contenthash:8].[ext]',
            publicPath: './dist/'
          }
        }
      }]
    },
    mode: 'none'
  };

Webpack 插件 plugin

用于扩展 Webpack 功能,虽然称为插件,但却是 Webpack 的骨干,Webpack 自身也是建立于插件系统上的

Webpack 使用插件只需要在配置项中增加一个 plugins 项即可。plugins 是一个数组,每一个数组元素是一个插件。

 const path = require('path');
  const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'bundle1.js'
    },
    plugins:[
      new CleanWebpackPlugin()    
    ],
    mode: 'none'
  };

通常 plugins 数组每一个元素都是插件构造函数 New 出来的实例,根据每一个插件的特点,可能会需要向其参数里传递各种配置参数。现在的插件基本都有默认配置,可以免去配置,只有在需要特殊处理时,进行手动配置参数。


clean-webpack-plugin

是一个清除文件的插件,每次打包后,磁盘空间会存有打包后的资源,在此打包时,需要先将本地已有的打包资源清除,减少对磁盘的占用。

使用插件时,首先要安装模块,然后通过 `require()` 函数导入进配置文件,才能在 plugins 数组中 进行 new 方法。

var path = require('path');
  var { CleanWebpackPlugin } = require('clean-webpack-plugin');
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'bundle.js',
      // filename: 'bundle2.js',
    },
    plugins:[
      new CleanWebpackPlugin()    
    ],
    mode: 'none'
  };

copy-webpack-plugin

用于复制文件,有时,有些本地资源在打包时并没有任何模块使用到,但是却想要把它们放在打包后的资源输出目录,预处理器不适合这么做,插件可以。

 var path = require('path');
  var CopyPlugin = require("copy-webpack-plugin");
  module.exports = {
    entry: './a.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'bundle.js'
    },
    plugins:[
     new CopyPlugin({
       patterns: [
         { from: path.resolve(__dirname, 'src/img/'), to: path.resolve(__dirname, 'dist/image/') },
       ],
     }),
    ],
    mode: 'none'
  };

在使用 copy-webpack-plugin 时,需要传入参数,改参数是一个对象,参数对象的 patterns 属性就是设置从哪复制及复制到哪的,该属性是数组,数组每一项是对象,对象的 from 属性就是 从哪复制,to 属性是复制到哪


Webpack 开发环境配置

  • 开启监听模式

    webpack --watch
    
  • 使用 webpack-dev-server ( DevServer )

    webpack-dev-server 安装后可以通过在 Webpack 配置文件里增加与 entry output 同级的 devServer 配置项开启

    DevServer 除了支持文件监听和浏览器自动刷新外,还可以做到模块热替换。

    DevServer 开启了一个本地 HTTP 服务器,可以请求处理和转发,不需要使用本地文件预览,还支持 Source Map,方便调试

    默认使用工程目录下的 index.html 作为首页

Source Map

在进行打包之后,打包出口文件中的代码不再是原始文件中的代码了,并不利于开发调试

如果要在浏览器里直接看到打包前的代码,就需要 source map。

只需要在 Webpack 配置文件中增加一行配置即可

devtool: 'source-map'

在开发环境,可以对 devtool 取值为 eval-cheap-module-source-map,该配置值能保留loader处理前的原始代码信息,而打包速度也不错,是一个较佳的选择。


webpack 基础
http://localhost:8080/archives/f3125877-4f79-478c-b373-6329188a6573
作者
inksha
发布于
2024年09月14日
许可协议