Webpack学习 | 青训营笔记

98 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第1天

什么是Webpack

本质上是一种前端资源编译、打包工具

  • 多份资源文件打包成一个Bundle
  • 支持Babel、Eslint、TS、Less、Sass
  • 支持模块化处理css,图片等资源文件
  • 支持持续监听、持续构建
  • 支持代码分离

image.png

一、webpack使用

初始化配置

  1. 安装 npm i -D webpack webpack-cli
  2. 编辑配置文件 webpack.config.js
  3. 执行编译命令 npx webpack

编译打包应用

  1. 运行指令
  • 开发环境指令:webpack src/js/index.js -o build/js/built.js --mode=development

功能:打包编译js和json文件,并且能够将es6的模块化语法转换为浏览器能识别的语法

  • 生产环境指令 webpack src/js/index.js -o bulid/js/built.js --mode=production

功能:在开发配置功能上压缩代码

  1. webpack工作流程 image.png
  • 入口处理:从entry文件开始,启动编译流程
  • 依赖解析,从entry文件开始,根据requireorimport等语句找到依赖资源
  • 资源解析,根据module配置,调用资源转移器,将png、css等非标准js资源转义为js内容
  • 递归2,3,知道所有资源处理完成
  • 资源合并打包,将转译后的资源内容合并打包为可直接在浏览器运行的js文件
  1. 总结
  • webpack能处理js/json,不能处理css/img等其他资源
  • 生产环境和开发环境将ES6模块化编译成浏览器能识别的module

二、webpack开发环境的基本配置

  1. 创建配置文件
/*
    webpack.config.js  webpack配置文件
        作用:指示webpack干哪些活(当运行 webpack 指令时,会加载里面的配置)

    所有构件工具都是基于nodejs平台运行的,模块化默认采用commonjs(配置,项目src的使用es6的import)

*/

const { resolve } = require('path')   //resolve:处理绝对路径的方法

module.exports = {
    //webpack配置
    //=========== 1. 入口起点
    entry:'./src/index.js', 
    //=========== 2. 输出 
    output:{  
        filename:'built.js', //输出文件名
        //__dirname是nodejs的一个变量,代表当前文件(webpack.config.js)的目录绝对路径
        path:resolve(__dirname,'build'),  //输出路径,
    },
    //=========== 3. load的配置
    module:{ 
        rules:[
            //详细的loader配置
        ]
    },
    //=========== 4.plugins的配置
    plugins:[
        //详细的plugins配置
    ], 
    //=========== 5.mode 模式
    mode:'development',
    // mode:'production'
}
  1. 打包样式资源
  • 安装loader npm add -D css-loader style-loader
  • 安装'module'处理css文件
const path=require('path')
module.exports={
    entry:'./src/index',
    output:{
        filename:'[name].js',
        path:path.join(__dirname,'./dist'),
    },
    module:{ 
     rules:[
         //详细的loader配置 (不同的文件必须配置不同的loader处理)
         {   
             //匹配哪些文件 --- 使用正则
             test: /\.css$/,
             //使用哪些loader进行处理
             use: [  //use数组中的loader执行顺序:从右到左,从下到上
                 'style-loader', //创建style标签,将js中的css样式资源插入进去,添加到head中生效
                 'css-loader'   //将css文件编程commonjs模块加载到js中,里面的内容是样式字符串
             ]
         }],
    }
}
 
  • css文件在js中的引用
const styles=require('./index.css');
// or
import styles from './index.css' 
  1. 生成HTML资源
  • 安装依赖 npm i -D html-webpack-plugin
  • 声明产物出口'output'
/* 
    loader: 1.下载  2.使用(配置loader)
    plugins:    1.下载     2. 引入     3.使用
*/
const { path } = require('path')  
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry:'./src/index.js',
    output:{
        filename:'[name].js',
        path:path.join(__dirname,'./dist'),
    },
    plugins:[
        //html-webpack-plugin
        //功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(js/css)
        //需求:需要有结构的HTML文件,引入template配置
        new HtmlWebpackPlugin({
            template:'./src/index.html'  //复制./src/index.html
        })
    ],
    mode: 'development'
}

  1. 打包图片资源
  • 安装对应的loader npm i -D url-loader
  • 如果直接在index.html中通过img引入图片,那么打包后html中模板还是index.html内容。也就是src中的图片路径不变,但是打包后的图片文件命名都是hash值,根本获取不到图片。所以需要使用html-loader处理html文件的img图片
module:{
     rules:[
         {...},
         {
             //问题:默认处理不了html中img图片
             //处理图片资源
             test:/\.(jpg|png|gif)$/,
             //只有一个loader可以不使用user[]格式,这里需要下载url-loader和file-loader
             loader:'url-loader',  
             options:{
                 //图片大小小于8kb,就会被base64处理  --- 小图片处理(变成一串编码很长的字符串)
                 //优点:减少请求数量(减轻服务器压力)
                 //缺点:图片体积会更大(文件请求速度变慢)
                 limit: 8*1024,   
                 /*
                     问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
                     解析时会出问题: 打包的html中img的url变成 [object module]
                     解决: 关闭url-loader的es6模块,使用commonjs解析 --- esModule:false

                     但是:在新版本的html-loader中这个问题已经被修复了,所以不关闭es6模块解析也没问题
                 */
                 esModule:false,
                 //给图片重命名(原本默认打包后的图片命名是长串的hash值)
                 //[hash:10]取图片的hash的前10位,[ext]取原来文件的扩展名
                 name:'[hash:10].[ext]'
             }
         },
         {
             test: /\.html$/,
             loader: 'html-loader'  //处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
         }
     ]
 },

三、Loader

Webpack Loader只是实现内容转换器-将各式各样的资源转换为标注js内容格式。

  • css-loader 将 css 转换为 __WEBPACK_DEFAULT_EXPORT__ = ".a{ xxx }" 格式
  • html-loader 将 html 转换为 __WEBPACK_DEFAULT_EXPORT__ = "<!DOCTYPE xxx" 格式
  • vue-loader 更复杂一些,会将 .vue 文件转化为多个 JavaScript 函数,分别对应 template、js、css、custom block

?为什么要使用loader?

webpack只认识符合js规范的文本:在构建make阶段,解析模块内容时会调用acorn将文本转换为AST对象,进而分析代码结构,分析模块依赖;这时候对图片、json、Vue SFC等场景不work了,就需要Loader介入将资源转化为Webpack可以理解的内容形式

Loader编写

module.exports=function(source,sourceMap?,data?){
    return source;
}

Loader 函数接收三个参数,分别为:

  • source:资源输入,对于第一个执行的 loader 为资源文件的内容;后续执行的 loader 则为前一个 loader 的执行结果
  • sourceMap: 可选参数,代码的 sourcemap 结构
  • data: 可选参数,其它需要在 Loader 链中传递的信息,比如 posthtml/posthtml-loader 就会通过这个参数传递参数的 AST 对象

Loader链式调用

使用上,可以为某种资源文件配置多个 Loader,Loader 之间按照配置的顺序从前到后(pitch),再从后到前依次执行,从而形成一套内容转译工作流,例如对于下面的配置:

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

image.png

  • less-loader:实现 less => css 的转换,输出 css 内容,无法被直接应用在 Webpack 体系下
  • css-loader:将 css 内容包装成类似 module.exports = "${css}" 的内容,包装后的内容符合 JavaScript 语法
  • style-loader:做的事情非常简单,就是将 css 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签

链式调用好处:一是保持单个 Loader 的单一职责,一定程度上降低代码的复杂度;二是细粒度的功能能够被组装成复杂而灵活的处理链条,提升单个 Loader 的可复用性。