了解Webpack并处理样式文件

目录

引入

随着前端的快速发展,目前前端的开发已经变的越来越复杂了:

  • 比如开发过程中我们需要通过模块化的方式来开发

  • 比如通过ES6+、TypeScript开发脚本逻辑,通过sass、 less等方式来编写css样式代码

  • 比如开发完成后我们还需要将代码进行压缩、合并以及其他相关的优化

但是对于很多的前端开发者来说,并不需要思考这些问题,日常的开发中没有面临这些问题

  • 是因为目前前端开发我们通常都会直接使用三大框架来开发:Vue、React、Angular

  • 但是事实上,这三大框架的创建过程我们都是借助于脚手架(CLI)的

  • Vue-CLI、create-react-app、Angular-CLI都是基于webpack来帮助我们支持模块化、lessTypeScript、打包优化的

  • Webpack 作为前端资源构建工具+静态模块打包器,是面试中的重中之重,我们有学习的必要

定义

webpack的官方文档是 https://webpack.js.org/webpack的中文官方文档是https://webpack.docschina.org/DOCUMENTATION:文档详情是有助于理解的

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

  • 打包bundlerwebpack可以将帮助我们进行打包,所以它是一个打包工具

  • 静态的static:最终可以将代码打包成最终的静态资源(部署到静态服务器)

  • 模块化modulewebpack默认支持各种模块化开发,ES Module、CommonJS、AMD

  • 现代的modern :正是因为现代前端开发面临各种各样的问题,才催生了webpack的出现和发展

安装和使用

Webpack的运行是依赖Node环境的 ,所以电脑上必须有Node环境,再安装webpack

  • 先安装Node.js,同时会安装npmNode官方网站:https://nodejs.org/

  • webpack的安装目前分为两个:webpack、webpack-cli

    • npm install webpack webpack-cli --g: 全局安装

    • npm install webpack webpack-cli --D: 局部安装

    • webpackwebpack-cli什么关系呐?

      1. 执行webpack命令,会执行node_modules下的.bin目录下的webpack

      2. webpack在执行时是依赖webpack-cli,如果没有安装就会报错

      3. 因为Webpack-cli是Webpack的命令行接口 ,它提供了许多有用的命令来帮助开发者管理Webpack项目

      4. Webpack-cli可以理解成Webpack的'管家',它负责接收并解析命令行参数

      5. webpack-cli解析完命令行时,它调用相应的Webpack插件或功能来执行任务 ,才是真正利用webpack进行编译和打包的过程

      6. 所以在安装webpack时,需要同时安装webpack-cli

      7. 第三方的脚手架事实上是没有使用webpack-cli ,而是类似于自己的vue-service-cli的东西

  • 前面安装完就可以在项目使用webpack了:

    1. 使用 npm init创建package.json文件,用于管理项目的信息、库依赖等

    2. 使用 npm install webpack webpack-cli -D安装局部的webpack

    3. 若全局也安装了webpack使用npx webpack命令打包 ,全局没安装使用webpack命令

    4. 也可以在package.json创建"scripts": {"build": "webpack"}脚本 ,使用 npm run build 执行脚本打包

  • 打包会发生什么?

    • 当运行webpack命令时,webpack会查找当前目录下的 src/index.js作为入口,如果没有此文件就报错

    • 从入口开始,会生成一个依赖关系图 ,包含应用程序中所需的所有模块(比如.js文件、css文件、图片、字体等)

    • 然后遍历图结构,打包一个个模块(根据文件的不同使用不同的loader来解析)

    • 打包完会在目录下会生成一个dist文件夹,里面存放一个main.js的文件,就是打包之后的文件

    • main.js中的代码会被压缩和丑化 ,代码仍存在ES6语法,比如箭头函数、const等,webpack不会自动转化需要我们后面配置

配置文件

在通常情况下,webpack需要打包的项目是非常复杂的 ,并且我们需要一系列的配置来满足要求,默认配置必然是不可以的

命令配置

webpack打包命令改变配置:

  • 配置webpack打包入口文件(默认src/index.jswebpack --entry ./src/main.js ,会打包./src/main.js,只有这一次打包生效

  • 配置webpack打包出口文件(默认dist/main.jswebpack --output-path ./build ,会打包代码,生成bulid文件夹

  • 配置webpack打包后的文件名(默认distwebpack --output-filename bundle.js ,打包代码并生成bundle.js文件

  • 三者可以随意混合使用 :比如 webpack --entry ./src/main.js --output-filename bundle.js

  • 想要每次打包生效需要在package.json配置"scripts": {"build": "写想要的webpack命令"} ,然后打包执行 npm run build 就可以了

单独文件

也可以在根目录下创建一个webpack.config.js文件,来作为webpack的配置文件:

js 复制代码
// package.json
{
  "name": "webpack-study",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.95.0",
    "webpack-cli": "^5.1.4"
  }
}


// webpack.config.js
module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "index.js",
    path: "/build", // 必须是绝对路径
  },
};

这时 npm run build 执行完发现,在项目目录下根本没有打包成功的文件夹,但我们在C盘看到了打包的文件,可想而知肯定是输出path配错了

那么我们就需要结合Node知识进行修改path了,修改后打包就能看到在当前根目录已经有了build文件夹,Node具体学习这篇文章:https://blog.csdn.net/qq_45730399/article/details/142339453?spm=1001.2014.3001.5501

js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "index.js",
    /* 
      __dirname: 绝对路径,获取当前⽂件所在的路径,不包括后⾯的⽂件名
      path.resolve(): 将参数解析为绝对路径
      下面两行代码都可以
    */
    // path: path.resolve(__dirname, "./build"),
    path: path.resolve(__dirname, "build"),
  },
};

指定文件

如果配置文件并不是webpack.config.js的名字 ,这个时候可以通过 webpack --config 你的配置文件名字 来打包并指定对应的配置文件

  • 如果还是使用webpack命令打包不会报错,只是会使用默认的打包配置,配置文件无效

  • 每次执行命令对源码编译非常繁琐,可以package.json中配置"scripts": {"build": "webpack --config wk.config.js"}

处理样式

js 复制代码
// index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- 引入我们打包后的js文件 -->
    <script src="../build/bundle.js"></script>
  </body>
</html>

// index.js
import "./style.css";

const divEl = document.createElement("div");
divEl.innerHTML = "hello world";
divEl.className = "box";
document.body.appendChild(divEl);

// style.css
.box {
  color: coral;
  font-size: 20px;
  font-weight: bold;
}

我们写了上面代码执行打包命令,然后发现报错了,读错误说也许需要一个loader处理css文件 ,这就是下面要学习的loader

css-loader

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

  • loader 可以用于对模块的源代码进行转换

  • 可以css文件也看成是一个模块 ,我们是通过import来加载这个模块的

  • 加载这个模块时,webpack不知道如何对其进行加载 ,必须制定对应的loader来完成这个功能

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

  • npm install css-loader -D安装css-loader

使用

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

  • 内联方式import "css-loader!./style.css" 内联方式使用较少,因为不方便管理

  • CLI方式(webpack5中不再使用) :在webpack5的文档中已经没有了--module-bind,实际应用中也比较少使用

  • 配置方式 :在webpack.config.js文件中写明配置信息

配置信息解释如下:

  • module.rules中允许配置多个loader (因为会使用其他的loader,完成其他文件的加载)

  • 这种方式可以更好的表示loader的配置,也方便后期的维护,同时也让你对各个Loader有一个全局的概览

  • module.rules的配置如下:

    • rules属性对应的值是一个数组:[Rule]
    • Rule是一个对象,对象中可以设置多个属性:
      1. test属性: 用于对 resource(资源)进行匹配的,会设置成正则表达式

      2. use属性: 对应的值是一个数组:[UseEntry],UseEntry是一个对象,可以通过对象的属性来设置一些其他属性

        loader必须有一个 loader属性,对应的值是一个字符串

        options :可选的属性,值是一个字符串或者对象 ,值会被传入到loader

      3. loader属性 : 字符串,单个规则只能有一个 loader 属性 ,如果需要使用多个 loaderloader 属性只能指定一个 loader,应该使用 use 数组

    js 复制代码
    // wk.config.js
    const path = require("path");
    
    module.exports = {
      entry: "./src/index.js",
      output: {
        filename: "index.js",
        path: path.resolve(__dirname, "build"),
      },
      module: {
        rules: [
          {
            test: /\.css$/,
            // use: ["css-loader"], // 写法一
    
            // use: [ // 写法二
            //   {
            //     loader: "css-loader",
            //     options: {},
            //   },
            // ],
    
            loader: "css-loader", // 写法三
          },
        ],
      },
    };

配置并打包完之后在打包文件中能看到css代码,但发现页面样式无效 ,因为还需要借另一个loaderstyle插入页面

style-loader

  • css-loader只负责将.css文件进行解析 ,不会将解析之后的css插入到页面中

  • 如果希望完成插入style的操作,需要另外一个loader ,就是 style-loader

  • npm install style-loader -D :安装style-loader

  • 在配置文件中添加style-loaderloader的执行顺序是倒着的 ,需要将style-loader写到css-loader的前面

js 复制代码
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "index.js",
    path: path.resolve(__dirname, "build"),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"], // 写法一

        // use: [ // 写法二
        //   {
        //     loader: "style-loader",
        //     options: {},
        //   },
        //   {
        //     loader: "css-loader",
        //     options: {},
        //   },
        // ],
      },
    ],
  },
};

less-loader

在开发中,可能会使用less、sass、stylus的预处理器来编写css样式,效率会更高,想让环境支持这些预处理器,需要把less、sass等编写的css需要通过工具转换成普通的css

  • npm install less -D :下载less

  • 编写style.less代码

    js 复制代码
    // style.less
    @fontSize: 20px;
    @fontWeight: bold;
    
    .box {
      color: red;
      font-size: @fontSize;
      font-weight: @fontWeight;
    }
  • index.js文件中引入import "./style.less"

  • 尝试打包会报下图错误

  • npm install less-loader -D :下载less-loader

  • 配置wk.config.jsless-loader 应该放在最后 ,因为需要让less-loader先把less转成css,在用css-loader解析css

    js 复制代码
    const path = require("path");
    
    module.exports = {
      entry: "./src/index.js",
      output: {
        filename: "index.js",
        path: path.resolve(__dirname, "build"),
      },
      module: {
        rules: [
          {
            test: /\.css$/,
            use: ["style-loader", "css-loader"],
          },
          {
            test: /\.less$/,
            use: [
              {
                loader: "style-loader",
              },
              {
                loader: "css-loader",
              },
              {
                loader: "less-loader",
              },
            ],
          },
        ],
      },
    };

PostCSS

PostCSS是一个通过JavaScript来转换样式的工具 ,可以帮助进行一些CSS的转换和适配,比如自动添加浏览器前缀、css样式的重置,postcss需要有对应的插件才会起效果,只要包括:

  • 自动前缀 :使用插件如 autoprefixer 自动添加浏览器前缀。

  • CSS 变量 :允许使用 CSS 变量和自定义属性。

  • 未来的 CSS 语法 :通过 postcss-preset-env 等插件使用未来 CSS 特性。

  • 模块化 :与 CSS Modules 等结合使用,实现更好的模块化支持。

postcss-loader

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

  • npm install postcss-loader -D :安装postcss-loader

  • npm install autoprefixer -D :需要添加前缀,就安装autoprefixer

  • 这时就可以增加配置了,样式user-select就会被加上前缀来适配浏览器 -webkit-user-select: none; -moz-user-select: none; user-select: none

js 复制代码
// style.less 
@fontSize: 20px;
@fontWeight: bold;

.box-less {
  height: 60px;
  color: red;
  font-size: @fontSize;
  font-weight: @fontWeight;
  user-select: none;
  background-color: #f0a4a466;
}


// wk.config.js
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "index.js",
    path: path.resolve(__dirname, "build"),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader", "postcss-loader"],
      },
      {
        test: /\.less$/,
        use: [
          "style-loader",
          "css-loader",
          "less-loader",
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                // plugins: ["autoprefixer"], // 也可以直接传入字符串
                plugins: [require("autoprefixer")], 
              },
            },
          },
        ],
      },
    ],
  },
};
  • 单独的postcss配置文件:在根目录下创建postcss.config.jswk.config.js中还是要写postcss-loader的,只是它插件的配置放单独文件
js 复制代码
// wk.config.js
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "index.js",
    path: path.resolve(__dirname, "build"),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader", "postcss-loader"],
      },
      {
        test: /\.less$/,
        use: [
          "style-loader",
          "css-loader",
          "less-loader",
          {
            loader: "postcss-loader",
            // options: {
            //   postcssOptions: {
            //     plugins: [require("autoprefixer")],
            //   },
            // },
          },
        ],
      },
    ],
  },
};


// postcss.config.js
module.exports = {
  plugins: [require("autoprefixer")],
};

postcss-preset-env

事实上,在配置postcss-loader时,配置插件并通常不使用autoprefixer,而使用另外一个插件:postcss-preset-env,因为它更强大

  • postcss-preset-env也是一个postcss的插件,会自动帮助我们添加autoprefixer (已经内置了autoprefixer

  • 可以将一些现代的CSS特性,转成大多数浏览器认识的CSS,会根据目标浏览器或者运行时环境添加所需的 polyfillsPolyfills 是一些代码(通常是 JavaScript)用来实现不被某些浏览器原生支持的特性)

  • npm install postcss-preset-env -D :安装postcss-preset-env

  • 直接把之前的autoprefixer改为postcss-preset-env ,查看打包后打码可以发现它不仅加了前缀,还把less文件中的背景颜色转成浏览器能识别的 background-color: rgba(240, 164, 164, 0.4)

js 复制代码
// wk.config.js
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "index.js",
    path: path.resolve(__dirname, "build"),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader", "postcss-loader"],
      },
      {
        test: /\.less$/,
        use: [
          "style-loader",
          "css-loader",
          "less-loader",
          {
            loader: "postcss-loader",
            // options: {
            //   postcssOptions: {
            //     plugins: [require("postcss-preset-env")],
            //   },
            // },
          },
        ],
      },
    ],
  },
};


// postcss.config.js
module.exports = {
  plugins: [require("postcss-preset-env")],
};
相关推荐
码客前端9 小时前
理解 Flex 布局中的 flex:1 与 min-width: 0 问题
前端·css·css3
Komorebi゛9 小时前
【CSS】圆锥渐变流光效果边框样式实现
前端·css
工藤学编程9 小时前
零基础学AI大模型之CoT思维链和ReAct推理行动
前端·人工智能·react.js
徐同保9 小时前
上传文件,在前端用 pdf.js 提取 上传的pdf文件中的图片
前端·javascript·pdf
怕浪猫9 小时前
React从入门到出门第四章 组件通讯与全局状态管理
前端·javascript·react.js
欧阳天风10 小时前
用setTimeout代替setInterval
开发语言·前端·javascript
EndingCoder10 小时前
箭头函数和 this 绑定
linux·前端·javascript·typescript
郑州光合科技余经理10 小时前
架构解析:同城本地生活服务o2o平台海外版
大数据·开发语言·前端·人工智能·架构·php·生活
沐墨染10 小时前
大型数据分析组件前端实践:多维度检索与实时交互设计
前端·elementui·数据挖掘·数据分析·vue·交互
xkxnq10 小时前
第一阶段:Vue 基础入门(第 11 天)
前端·javascript·vue.js