手把手带你学webpack(1)-- Web初体验

717 阅读7分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

该专栏会带你从零学习webpack,一步步由浅入深地了解webpack的原理以及如何使用,还会教你如何自定义loaderplugin,以及webpack性能优化,如Tree Shakinggzip压缩等

希望在读完本专栏后,能够让你灵活使用webpack,从而更好地解决工作中项目构建时遇到的问题,以及知道该如何对项目的构建进行性能优化

本篇文章是该专栏的第一章,会带你体验一下webpack,让你大体上了解一下webpack是干什么用的

本专栏对应的github仓库:github.com/Plasticine-…

1. Webpack是什么?

webpack is a static module bundler for modern JavaScript applications.

这是官网对webpack的概念解释

  1. bundler说明它是一个打包工具
  2. static说明能够处理各种静态资源
  3. module说明支持模块化开发,比如各种模块化方案ES ModuleCommon JSAMD

综上,可以大概了解到,webpack是一个能够将项目中用到的各种静态资源、模块化js代码打包成最终可以部署在服务器上直接使用,能够直接被浏览器解析运行的构建工具


2. 安装webpack

pnpm i webpack webpack-cli -D

3. webpack和webpack-cli的关系

一般来说需要安装webpackwebpack-cliwebpack-cli是在命令行中使用webpack时必须安装的依赖,安装了之后就能在命令行使用webpack命令了

但是它不是必须的,比如一些第三方脚手架工具,如vue-cli,其内部就只装了webpack而没有装webpack-cli,它有自己的vue-service-cli能够实现类似的功能


4. 体验webpack

首先在项目目录下创建一个src目录,并在其中创建index.js文件,然后写入一些代码

// src/index.js
console.log('hello webpack!');

然后执行npx webpack后会发现,项目目录下多出了dist目录,并且有一个main.js文件,其内容和我们的index.js一模一样

由此可以发现,webpack在没有配置的时候,默认是以src/index.js作为入口文件,dist/main.js作为打包的结果


5. webpack配置文件

可以在项目目录下创建webpack.config.jswebpack进行一些个性化配置,比如上面的入口文件默认是src/index.js,出口是dist/main.js,我们可以对其作出修改

// webpack.config.js
const path = require('path');

module.exports = {
  entry: path.resolve(__dirname, 'src/main.js'),
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'build'),
  },
};

pathNode.js的内置模块,用于处理路径相关的操作,path.resolve()就是用于拼接路径,第一个参数传入了__dirname表示当前文件webpack.config.js所在目录,然后拼接上src/main.js,最终就会得到D:/webpack_learning/01_webpack_start/src/main.js这样的绝对路径了


5.1 vscode编写webpack配置时提供自动补全

如果直接像上面那样去写webpack.config.js的时候是没有自动补全的,webpack的配置项那么多,一直去官网查对应配置项还是挺麻烦的,只需要添加上注释,并且用@type注解声明导出的对象的类型,就可以获得自动补全提示了!

/**
 * @type { import('webpack').Configuration }
 */
module.exports = {
  entry: path.resolve(__dirname, 'src/main.js'),
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'build'),
  },
};

写相应配置项的时候还能够看到对应的配置项的作用(和官网的一致),省去了不少查文档的时间 image.png


5.2 指定配置文件名字

默认的配置文件名是webpack.config.js,如果想要使用别的名字,可以在执行webpack命令的时候加上--config参数,然后带上配置文件的路径即可

比如我希望使用webpack.test.config.js作为配置文件,那么应当这样执行命令

npx webpack --config ./webpack.test.config.js

5.3 将webpack命令作为package.json的脚本

如果我们指定了默认配置文件名以外的配置文件时,每次都要输入npx webpack --config ./webpack.test.config.js这样一长串太麻烦了,可以直接将其写在package.jsonscripts配置项中

"scripts": {
  "build": "webpack --config ./webpack.test.config.js"
},

注意:写在**scripts**中的命令不需要再加上**npx**


6. webpack初体验案例

6.1 案例场景和环境搭建

在这个案例中,我们会在js中直接用import导入css文件,看看导入的css文件能否生效

首先准备一下环境,在项目根目录下创建index.html,并在其中引入打包后的js文件

<!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 start</title>
  </head>
  <body>
    <script src="../dist/bundle.js"></script>
  </body>
</html>

然后在src/css中创建index.css,并写好一些样式

* {
  padding: 0;
  margin: 0;
}

html,
body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  width: 100%;
  background-color: #1d3557;
}

.box {
  height: 500px;
  width: 500px;
  background-color: #457b9d;
}

然后再在入口文件中导入该css文件,并使用js创建一个classboxdiv元素

// src/index.js
import './css/index.css';

(() => {
  const boxEl = createEl('div', 'box');

  document.body.appendChild(boxEl);
})();

/**
 * 创建指定标签和类名的 DOM 元素
 * @param {string} elTag 标签名
 * @param {string} className 类名
 * @returns HTMLElement DOM 元素
 */
function createEl(elTag, className) {
  const el = document.createElement(elTag);

  el.className = className;

  return el;
}

6.2 初探loader

执行npx webpack,却遇到了如下报错 image.png 提示我们缺少了处理这种类型文件的loaderloaderwebpack的一个重要概念,在依赖图中遇到的各种类型文件时,要有相应的loader去处理才能正常打包,之后的文章中会详细介绍loader,这里先简要介绍一下loader是干什么的:

  1. 可以用于对模块的源代码进行转化
  2. 由于我们是通过import导入css文件的,因此index.css可以被看成是一个模块
  3. 加载该模块的时候,webpack并不知道要如何处理css这种类型的模块,因此需要有一个特定的loader去处理,让它能够顺利被webpack加载

那么什么loader能够处理css类型的模块呢?答案就是css-loader


6.3 安装并配置css-loader

首先需要安装css-loader

pnpm i css-loader -D

配置css-loader有三种方式:

  1. 内联方式
  2. CLI方式(webpack5中不再使用)
  3. 在配置文件中配置

下面逐一介绍这三种模式

6.3.1 内联方式

直接在导入相应模块的时候指明使用的loader,因而被称为内联方式

import 'css-loader!./css/index.css';

这种方式很少用,因为不方便管理,并且每次导入css都要手动声明一下,不太方便使用


6.3.2 CLI方式

该方式在webpack5中已经被取消,下面是webpack4文档中关于该方式的介绍 image.png 根据官方文档,我们使用这种方式打包的命令如下

npx webpack --module-bind 'css=css-loader'

但是由于我们安装的是webpack5,已经不支持该参数了,所以会报错,但是没关系,这种方式了解即可,实际开发中并不会这样去使用loader image.png


6.3.3 配置文件中配置

这种方式是最常用的,意思是在webpack.config.js中的module.rules下配置loader

这种方式方便后期维护,能够一目了然,知道项目中用到了哪些loader,以我们的css-loader为例,看一下要怎么配置吧!

const path = require('path');

/**
 * @type { import('webpack').Configuration }
 */
module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        // 也可以直接用 test 简写
        resource: {
          test: /\.css/,
        },
        // rules.use 中的 loader 还可以直接简写为 rules.loader
        use: [
          // 需要给 loader 提供配置项的时候使用对象形式
          // 不需要提供配置时直接用字符串即可
          // 即 use: ['css-loader']
          {
            loader: 'css-loader',
            options: {
              xxx: 'options item',
            },
          },
        ],
      },
    ],
  },
};

webpack的配置有很多都可以简写,这一点可以在写的时候注意一下自动补全中的文档提示 image.png 由于我们暂时不需要用到css-loader的配置项,因此直接在rules.use中写上字符串就好了

const path = require('path');

/**
 * @type { import('webpack').Configuration }
 */
module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css/,
        use: ['css-loader'],
      },
    ],
  },
};

6.4 使用style-loader

现在我们配置完了,并且打包也正常了,可是通过live-server运行一个服务器,然后访问index.html的时候却发现样式并没有生效 image.png 这是为什么呢? 因为css-loader只是负责解析.css文件类型的模块,但是并不会将解析后的结果插入到html中 如果希望将解析后的css样式插入到html中,还需要另外一个loader -- style-loader

安装style-loader

pnpm i style-loader -D

然后将style-loader配置到webpack.config.js

const path = require('path');

/**
 * @type { import('webpack').Configuration }
 */
module.exports = {
  entry: path.resolve(__dirname, 'src/index.js'),
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css/,
        // 一定要将 style-loader 写在 css-loader 前面,因为 webpack 是逆序使用 loader 的
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
};

执行pnpm run build后就能够看到效果了 image.png 查看打包后的结果可以发现,会在html中的head标签中创建一个style标签,并将样式放在这里面 image.png 后续我会讲解如何将css抽取到单独的文件中,并进行压缩等操作