Skip to content

一. 认识webpack工具


1. 内置模块path

  • path模块用于对路径和文件进行处理,提供了很多好用的方法
  • 我们知道在Mac OSLinux和`window上的路径时不一样的
    • window上会使用\或者\\来作为文件路径的分隔符,当然目前也支持/
    • Mac OSLinuxUnix操作系统上使用/来作为文件路径的分隔符
  • 那么如果我们在window上使用\来作为分隔符开发了一个应用程序,要部署到Linux上面应该怎么办呢?
    • 显示路径会出现一些问题
    • 所以为了屏蔽他们之间的差异,在开发中对于路径的操作我们可以使用path模块,node会根据操作系统自动处理对应的路径
  • 可移植操作系统接口(英语:Portable Operating System Interface,缩写为POSIX
    • LinuxMac OS都实现了POSIX接口
    • Window部分电脑实现了POSIX接口

2. path常见的API

  • 从路径中获取信息

    • path.dirname(filepath):获取文件的父文件夹
      • __dirname: 当前模块的所在目录名,全局可使用,但实际并不是全局对象
    • path.basename(filepath):获取文件名
    • path.extname(filepath):获取文件扩展名
      • __filename: 当前模块的文件名
    js
        const path = require('path')
        const filepath = 'C://abc/cba/nba.txt'
        console.log(path.dirname(filepath)) // C://abc/cba
        console.log(path.basename(filepath)) // nba.txt
        console.log(path.extname(filepath)) // .txt
  • 路径的拼接:path.join(...paths)

    • 如果我们希望将多个路径进行拼接,但是不同的操作系统可能使用的是不同的分隔符
    • 这个时候我们可以使用path.join函数
    js
        const path = require('path')
        const path1 = "/abc/cba"
        const path2 = "../aaa/bbb/ccc.txt"
        const path3 = "./ddd/eee.js"
        console.log(path.join(path1, path2)) // \abc\aaa\bbb\ccc.txt
        console.log(path.join(path1, path3)) // \abc\cba\ddd\eee.js
        console.log(path.join(path2, path3)) // ..\aaa\bbb\ccc.txt\ddd\eee.js
        console.log(path.join(path3, path2)) // ddd\aaa\bbb\ccc.txt
  • 拼接绝对路径:path.resolve()

    • path.resolve方法会把一个路径或路径片段的序列解析为一个绝对路径
    • 给定的路径的序列是从右往左被处理的,后面每个path被依次解析,直到构造完成一个绝对路径,\绝对路径,指当前文件所作的根目录
    • 如果在处理完所有给定path的段之后,还没有生成绝对路径,则使用当前工作目录
    • 生成的路径被规范化并删除尾部斜杠,零长度path段被忽略
    • 如果没有path传递段,path.resolve()将返回当前工作目录的绝对路径(当前模块所在的目录名)
    js
        const path = require('path')
        const path1 = "/abc/cba"
        const path2 = "../aaa/bbb/ccc.txt"
        const path3 = "./ddd/eee.js"
        // 注意:当前文件所在目录:C:\Users\23634\Desktop\learn\
        console.log(path.resolve(path1, path2, path3)) // C:\abc\aaa\bbb\ccc.txt\ddd\eee.js
        console.log(path.resolve(path3)) // C:\Users\23634\Desktop\learn\ddd\eee.js
        console.log(path.resolve('./hello/', '')) // C:\Users\23634\Desktop\learn\hello 
        console.log(path.resolve()) // C:\Users\23634\Desktop\learn

3.在webpack中的使用

  • webpack中获取路径或者起别名的地方也可以使用

    image-20220724181510833

4.认识webpack

  • 事实上随着前端的快速发展,目前前端的开发已经变的越来越复杂了:
    • 比如开发过程中我们需要通过模块化的方式来开发
    • 比如也会使用一些高级的特性来加快我们的开发效率或者安全性,比如通过ES6+TypeScript开发脚本逻辑,通过sassless等方式来编写css样式代码
    • 比如开发过程中,我们还希望实时的监听文件的变化来并且反映到浏览器上,提高开发的效率
    • 比如开发完成后我们还需要将代码进行压缩、合并以及其他相关的优化等…
  • 但是对于很多的前端开发者来说,并不需要思考这些问题,日常的开发中根本就没有面临这些问题:
    • 这是因为目前前端开发我们通常都会直接使用三大框架来开发:VueReactAngular
    • 但是事实上,这三大框架的创建过程我们都是借助于脚手架(CLI)的
    • 事实上Vue-CLIcreate-react-appAngular-CLI都是基于webpack来帮助我们支持模块化、lessTypeScript、打包优化等的

5.脚手架依赖webpack

  • 事实上我们上面提到的所有脚手架都是依赖于webpack的:
image-20220724183315239

6.Webpack到底是什么呢?

  • 我们先来看一下官方的解释:

    image-20220724183349532
  • webpack是一个静态的模块化打包工具,为现代的JavaScript应用程序

  • 我们来对上面的解释进行拆解:

    • 打包bundlerwebpack可以将帮助我们进行打包,所以它是一个打包工具
    • 静态的static:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器)
    • 模块化modulewebpack默认支持各种模块化开发,ES ModuleCommonJSAMD
    • 现代的modern:我们前端说过,正是因为现代前端开发面临各种各样的问题,才催生了webpack的出现和发展

7.Vue项目加载的文件有哪些呢?

  • JavaScript的打包:
    • ES6转换成ES5的语法
    • TypeScript的处理,将其转换成JavaScript
  • CSS的处理:
    • CSS文件模块的加载、提取
    • LessSass等预处理器的处理
  • 资源文件imgfont
    • 图片img文件的加载
    • 字体font文件的加载
  • HTML资源的处理:
    • 打包HTML资源文件
  • 处理vue项目的SFC文件.vue文件

8.Webpack的使用前提

  • webpack的官方文档是https://webpack.js.org/
    • webpack的中文官方文档是https://webpack.docschina.org/
    • DOCUMENTATION:文档详情,也是我们最关注的
  • Webpack的运行是依赖Node环境的,所以我们电脑上必须有Node环境
    • 所以我们需要先安装Node.js,并且同时会安装npm,也可以使用nvm或者n来管理Node版本

9.Webpack的安装

  • webpack的安装目前分为两个:webpackwebpack-cli(webpack4开始,安装webpack需要同时安装webpack-cli,此工具用于在命令行中运行 webpack)

  • 那么它们是什么关系呢?

    • 执行webpack命令,会执行node_modules下的.bin目录下的webpack
    • webpack在执行时是依赖webpack-cli的,如果没有安装就会报错
    • webpack-cli是在命令行里使用webpack必须要用的东西,因为其作用是能识别命令行
    • webpack-cli中代码执行时,才是真正利用webpack进行编译和打包的过程
    • 所以在安装webpack时,我们需要同时安装webpack-cli(第三方的脚手架事实上是没有使用webpack-cli的,而是类似于自己的vue-service-cli的东西)
    image-20220724184247584

二.webpack基本打包


1. Webpack的默认打包(重点)

  • 我们可以通过webpack进行打包,之后运行打包之后的代码

    • 在目录下直接执行webpack命令

      bash
      npx webpack
      # 或
      webpack
  • 生成一个dist文件夹,里面存放一个main.js的文件,就是我们打包之后的文件:

    • 这个文件中的代码被压缩和丑化了
    • 另外我们发现代码中依然存在ES6的语法,比如箭头函数、const等,这是因为默认情况下webpack并不清楚我们打包后的文件是否需要转成ES5之前的语法,后续我们需要通过babel来进行转换和设置
  • 我们发现是可以正常进行打包的,但是有一个问题,webpack是如何确定我们的入口的呢?

  • 事实上,当我们运行webpack时,webpack默认会查找当前目录下的src/index.js作为入口

  • 所以,如果当前项目中没有存在src/index.js文件,那么会报错

  • 导入时如果省略后缀名,webpack本身也会帮我们添加文件后缀名

  • 当然,我们也可以通过 cli 参数中来指定入口和出口

    bash
    # --entry 入口地址
    # --output-path 打包文件所在文件夹路径
    # --output-filename 打包文件名称
    npx webpack --entry ./src/main.js --output-path ./build --output-filename aaa.js
    • --output-path:配置打包后的文件夹路径
    • --output-filename:配置打包后的文件夹下面的源文件名称
  • 也可以选择在 webpack 配置文件中配置

    js
    const path = require('path')
    // const curDir = path.resolve()
    // console.log(curDir + '\\bundle') 
    
    module.exports = {
      entry: './src/main.js',
      output: {
        filename: 'aaa.js',
        // path: curDir + '\\bundle'
        // path: path.resolve('./bundle')
        path: path.resolve(__dirname, './bundle') // 必须是绝对路径
      }
    }
  • webpack的配置文件webpack.config.js文件名是固定的,而webpack是基于node运行的,跑在node的环境下,所以这个模块文件只能使用nodeCommonJS的模块化,不能使用别的模块化

  • 执行 npx webpack,默认会去当前目录下寻找配置文件 webpack.config.js

  • 如果需要修改指定配置文件名,使用npx webpack --config wk.config.js,或者package.json文件中配置scripts命令

2.创建局部的webpack

  • 前面我们直接执行webpack命令使用的是全局的webpack,如果希望使用局部的可以按照下面的步骤来操作

  • 第一步:创建package.json文件,用于管理项目的信息、库依赖等

    js
    	npm init -y // 自动生成默认配置信息
    	npm init // 手动设置配置信息
  • 第二步:安装局部的webpack(webpack4.x开始,这两个都需要安装)

    bash
    npm i webpack webpack-cli -D // webpack属于开发依赖
  • 第三步:使用局部的 webpack

    bash
    # 一般包都是需要使用 npx + 包 命令来搭配使用的,正常是不会去当前目录中的子目录中查找node_modules文件中对应的包
    npx webpack
    
    # webpack比较特殊,可以省略npx,会去当前目录的子目录中查找node_modules文件中对应的包
    webpack
  • 第四步:在package.json中创建scripts脚本,执行脚本打包即可

    js
        "scirpt": {
            "build": "webpack" // npm run build
        }

三. webpack配置文件


1.webpack.config.js配置文件

  • 在通常情况下,webpack需要打包的项目是非常复杂的,并且我们需要一系列的配置来满足要求,默认配置必然是不可以的
  • 我们可以在根目录下创建一个webpack.config.js文件,来作为webpack的配置文件:
image-20220724201239176

2.指定配置文件

  • 但是如果我们的配置文件并不是webpack.config.js的名字,而是其他的名字呢?
    • 比如我们将webpack.config.js修改成了wk.config.js
    • 这个时候我们可以通过--config来指定对应的配置文件
  • 但是每次这样执行命令来对源码进行编译,会非常繁琐,所以我们可以在package.json中增加一个新的脚本:
image-20220724201340537

四. 编写和打包CSS文件


1.Webpack的依赖图

  • webpack到底是如何对我们的项目进行打包的呢?

    • 事实上webpack在处理应用程序时,它会根据命令或者配置文件找到入口文件
    • 从入口开始,会生成一个 依赖关系图,这个依赖关系图会包含应用程序中所需的所有模块(比如js文件、css文件、图片、字体等)
    • 然后遍历图结构,打包一个个模块(根据文件的不同使用不同的loader来解析,webpack默认只会对js文件进行打包,内置功能
    image-20220724210011323

2.编写案例代码

  • 我们创建一个component.js

    • 通过JavaScript创建了一个元素,并且希望给它设置一些样式
    image-20220724211638617

3.css-loader的使用

  • 上面的错误信息告诉我们需要一个合适的loader来处理这个css文件,但是loader是什么呢?

    • loader 可以用于对模块的源代码进行转换
    • 我们可以将css文件也看成是一个模块,我们是通过import来加载这个模块的
      • 如果有一个模块只是为了引入,而没有导出任何的东西,这样就表示该模块加入到依赖图中了,这里是可以不写from
    • 在加载这个模块时,webpack其实并不知道如何对其进行加载,我们必须制定对应的loader来完成这个功能
  • 那么我们需要一个什么样的loader呢?

    • 对于加载css文件来说,我们需要一个可以读取css文件的loader
    • 这个loader最常用的是css-loader
  • css-loader的安装:

    js
    	npm i css-loader -D // loader打包时(开发阶段)依赖

4.css-loader的使用方案

  • 如何使用这个loader来加载css文件呢?有三种方式:

    • 内联方式
    • CLI方式(webpack5中不再使用)
    • 配置方式
  • 内联方式:内联方式使用较少,因为不方便管理

    • 在引入的样式前加上使用的loader,并且使用!分割

      js
      	import "css-loader!./css/style.css"
  • CLI方式

    • webpack5的文档中已经没有了--module-bind
    • 实际应用中也比较少使用,因为不方便管理

5.loader配置方式

  • 配置方式表示的意思是在我们的webpack.config.js文件中写明配置信息:
    • module.rules中允许我们配置多个loader(因为我们也会继续使用其他的loader,来完成其他文件的加载)
    • 这种方式可以更好的表示loader的配置,也方便后期的维护,同时也让你对各个Loader有一个全局的概览
  • module.rules的配置如下:
  • rules属性对应的值是一个数组:[Rule]
  • 数组中存放的是一个个的RuleRule是一个对象,对象中可以设置多个属性:
    • test属性:用于对resource(资源/文件)进行匹配的,通常会设置成正则表达式
    • use属性:对应的值时一个数组:[UseEntry]
      • UseEntry是一个对象,可以通过对象的属性来设置一些其他属性
        • loader:必须有一个loader属性,对应的值是一个字符串
        • options:可选的属性,值是一个字符串或者对象,值会被传入到loader
        • query:目前已经使用options来替代
      • 传递字符串(如:use: [ 'style-loader' ])是loader属性的简写方式(如:use: [ { loader: 'style-loader'} ])
    • loader属性: Rule.use: [ { loader } ] 的简写

6.Loader的配置代码

js
    const path = require('path')
    module.exports = {
      entry: './src/main.js',
      output: {
        filename: 'aaa.js',
        path: path.resolve(__dirname, './bundle')
      },
      module: {
        rules: [
          {
            test: /\.css$/, // 告诉webpack匹配什么文件
            use: [ // use多个loader使用顺序:从下往上 从右往左的
              { loader: 'style-loader' },
              { loader: 'css-loader' }
            ],
            // 简写一: 如果loader只有一个,可以省略use,直接写在外面
            loader: "css-loader",
            // 简写二: 多个loader不需要其他属性时, 可以直接写loader字符串形式
            use: [
              "style-loader",
              "css-loader"
            ]
          }      
        ]
      }
    }

7.认识style-loader

  • 我们已经可以通过css-loader来加载css文件了

    • 但是你会发现这个css在我们的代码中并没有生效(页面没有效果)
  • 这是为什么呢?

    • 因为**css-loader只是负责将.css文件进行解析,并不会将解析之后的css插入到页面中**
    • 如果我们希望再完成插入style的操作,那么我们还需要另外一个loader就是style-loader
  • 安装style-loader

    js
    	npm i style-loader -D // loader打包时(开发阶段)依赖

8.配置style-loader

  • 那么我们应该如何使用style-loader

    • 在配置文件中,添加style-loader
    • 注意:因为**loader的执行顺序是从右向左(或者说从下到上,或者说从后到前的)**,所以我们需要将style-loader写到css-loader的前面
    js
        use: [ // use多个loader使用顺序:从下往上 从右往左的 从后往前
          { loader: 'style-loader' },
          { loader: 'css-loader' }
        ]
  • 重新执行编译npm run build,可以发现打包后的css已经生效了:

    • 当前目前我们的css是通过页内样式的方式添加进来的
    • 后续我们也会讲如何将css抽取到单独的文件中,并且进行压缩等操作

五. 编写和打包less文件


1.如何处理less文件?

  • 在我们开发中,我们可能会使用lesssassstylus等预处理器来编写cs样式,效率会更高

  • 那么,如何可以让我们的环境支持这些预处理器呢?

    • 首先我们需要确定,lesssass等编写的css需要通过工具转换成普通的css
  • 比如我们编写如下的less样式:

    less
    	@fontSize: 30px;
    	@fontWeight: 700;
    	.content {
          font-size: @fontSize;
          font-weight: @fontWeight;
    	}

2.Less工具处理

  • 我们可以使用less工具来完成它的编译转换:

    js
    	npm i less -D
  • 执行如下命令:

    js
    	npx lessc ./src/css/title.less title css

3.less-loader处理

  • 但是在项目中我们会编写大量的css,它们如何可以自动转换呢?

    • 这个时候我们就可以使用less-loader,来自动使用less工具转换lesscss

      • less-loader依赖less,所以less的包也会被安装
      js
          npm i less-loader -D
  • 配置webpack.config.js

    js
          {
            test: /\.less$/,
            use: [ "style-loader", "css-loader", "less-loader" ] // less-loader先转换成css,然后css-loader处理...
          }

六.postcss工具处理CSS


1.认识PostCSS工具

  • use-select:none;让用户无法选中该元素,但是这个属性有一定兼容性问题,所以需要用到postcss来帮助我们判断属性是否需要添加浏览器前缀来做兼容
  • 什么是PostCSS呢?
    • PostCSS是一个通过JavaScript来转换样式的工具
    • 这个工具可以帮助我们进行一些CSS的转换和适配,比如自动添加浏览器前缀、css样式的重置
    • 但是实现这些功能,我们需要借助于PostCSS对应的插件
  • 如何使用PostCSS呢?主要就是两个步骤:
    • 第一步:查找PostCSS在构建工具中的扩展,比如webpack中的postcss-loader
    • 第二步:选择可以添加你需要的PostCSS相关的插件

2.postcss-loader

  • 我们可以借助于构建工具:

    • webpack中使用postcss就是使用postcss-loader来处理的

    • 我们来安装postcss-loader

      js
      	npm i postcss-loader -D // 开发打包时依赖
  • 我们修改加载cssloader:(配置文件已经过多,给出一部分了)

    • 注意:因为**postcss需要有对应的插件才会起效果**,所以我们需要配置它的plugin

3.单独的postcss配置文件

  • 因为我们需要添加前缀,所以要安装autoprefixer

    js
    	npm i autoprefixer -D
  • 我们可以将这些配置信息放到一个单独的文件中进行管理:

    • 在项目的根目录下创建postcss.config.js

      js
          module.exports = {
            plugins: [
              'autoprefixer' // 在使用某些postcss插件时,也可以直接传入字符串
              // require('autoprefixer') 
            ]
          }

4.postcss-preset-env

  • 事实上,在配置postcss-loader时,我们配置插件并不需要使用autoprefixer

  • 我们可以使用另外一个插件:postcss-preset-env

    • postcss-preset-env也是一个postcss的插件
    • 它可以帮助我们将一些现代的CSS特性,转成大多数浏览器认识的CSS,并且会根据目标浏览器或者运行时环境添加所需的polyfill
    • 也包括会自动帮助我们添加autoprefixer(所以相当于已经内置了autoprefixer
  • 首先,我们需要安装postcss-preset-env

    js
    	npm i postcss-preset-env -D
  • 之后,我们直接修改掉之前的autoprefixer即可:

    js
        module.exports = {
          plugins: [
            // 'autoprefixer' // 在使用某些postcss插件时,也可以直接传入字符串
            'postcss-preset-env' // 可以帮助十六进制颜色转换为rgba
          ]
        }
    • postcss-loaderless-loader没有前后顺序要求

Released under the MIT License.