驾驭webpack系列一:基础篇

572 阅读10分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

本文同时参与 「掘力星计划」  ,赢取创作大礼包,挑战创作激励金

前言

今天我们来讲一下webpack基础配置,并从0到1配置一个能够解析js,css的项目,同时添加热更新功能。文章代码入口webpack01(欢迎大家star🌟)。我写文章的风格是一定要弄懂为什么要有这个东西,如果我们只会应用,而不理解为什么存在,原理是什么,这样长期会让我们称为工具人。所以我得文章会有大篇叙述为什么,希望大家可以多多吸取其中精华。


为什么要讲webpack

因为webpack配置项复杂,概念多,易混淆,难以记忆,loader和plugin众多等等原因,导致我们望而生畏,不如去学点其他容易掌握的东西。所以基于上面的种种原因,我们一直没有真正的去驾驭webpack,所以我们今天开始webpack系列,就是让每一位同学能够真正的去驾驭webpack,为你所用

WX20211003-222151@2x.png


通过本篇文章我们能学到什么

  • 为什么需要webpack?
  • webpack可以实现哪些功能
  • webpack的工作流程是什么样子的
  • 从0到1配置一个能够解析js,css,开启热更新功能的项目

webpack一览

首先我们来讲一下webpack的概念,我们按照why,what,how的方式来进行讲解


为什么需要webpack?

在讲为什么需要webpack之前,我们先了解一下什么是工程化?

工程化其实也就是自动化,就是把一系列的流程用代码去实现,提高效率。

随着客户端的代码量越来越大,用户越来越多,庞大的代码量意味着我们需要适当的去组织代码,提高页面加载性能,提高交互能力,提高自动化部署,让程序员把更多的时间放在业务代码上。


webpack可以实现哪些功能

  • 代码转化 把一些浏览器不支持的语言比如typescript,coffeescript,react,es7,8,9,10,less等转化为被浏览器支持的html,js,css

  • 文件优化 压缩js,html,css,合并压缩图片

  • 代码分割 这个无疑是最重要的

我们需要一个更灵活的传输方式,在大多数情况下,如果能在极端中间找到一个平衡会是最好的选择。比方说,在编译所有的模块的时候可以把模块分割成很多小模块。这样一来,我们就可以把请求分成很多小请求,而分割后的模块只有在需要的时候才会被请求。所以初始的请求不会包含所有的代码,从而减小传输压力。至于代码怎么分割由程序员决定。

这个想法来源于Google's GWT. 更多的信息在code splitting.

  • 热更新 监听源代码的变化,自动从新构建,只刷新更改的部分

  • 根据环境打包出相应的代码 开发环境我们注重调试,生产环境我们更注重体验,体积小

  • 代码校验 在代码被提交到仓库之前需要校验代码是否符合规范,以及单元测试是否通过


webpack是什么?

Webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。


工作流程

webpack会递归Entry当中去找module,每次找到一个module都会根据loader去找出对应的转换规则。对当前module转换之后,再解析当前module依赖的module。

模块以Entry来进行单位分组,一个Entry和其所依赖的module被分配到同一个Chunk,webpack把这些chunk输出,在整个的流程当中webpack会在恰当的时机执行Plugins定义的逻辑。


一些基本概念

  • mode:模式。对应有开发模式、生产模式等

  • entry:入口,webpack开始构建的第一步从入口开始,可以抽象为输入

  • output:出口,在webpack经过一系列处理之后输出想要的代码并输出结果。

  • loader:模块转换器,用于把模块原内容按照需求转换成新内容。Webpack 对于 .jpg、.txt 等内容无法处理,就需要 file-loader、url-loader 等进行协助处理。

  • plugins:扩展插件,在 Webpack 构建流程中的特定时机注入拓展逻辑来改变构建结果或者做其他你想做的事情。


构建过程

创建package.json文件

首先我们创建一个目录,取名webpack01,名字有点随意哈

然后我们需要创建一个package.json文件

package.json文件是干什么用的?

每一个项目都需要一个 package.json 文件,它的作用是记录项目的配置信息,比如我们的项目名称、包的入口文件、项目版本等,也会记录所需的各种依赖,还有很重要的 script 字段,它指定了运行脚本命令的 npm 命令行缩写。

在命令行输入如下命令进行生成package.json

npm init -y

此时会在目录下面生成一个package.json文件

安装babel和webpack依赖,并进行webpack.config.js配置

安装必备babel和webpack依赖

 @babel/core  //核心
 @babel/preset-env //预设环境,解析es6语法
 babel-loader //对js文件进行babel解析
 webpack
 webpack-cli                  //可以使用命令运行webpack
 webpack-dev-server           // 可以启动localhost服务

注意:webpack尽量使用4版本,这样后面依赖多了以后,可以避免很多让人掉头发的错误的发生

接下来我们创建src目录 创建App.js文件

const name = "welcome to webpack";
export default {
  name,
};

创建index.js文件,这个是入口文件

import App from "./App.js";
console.log(App.name);

为什么我们要这样写,其实就是看import能不能用,因为import是es6的语法

现在目录结构是这个样子的

image.png

我们现在要实现的功能很简单,就是要输出console.log的值,打印出ws,就相当于测试一下。

接下来配置一下webpack.config.js

const path = require("path");
module.exports = {
  mode: "development", // 这是开发模式
  entry: path.join(__dirname, "./src/index.js"), // 这是入口文件
  output: {
    filename: "bundle.js", // 要打印的文件名
    path: path.join(__dirname, "./dist"),  // 输出的文件目录
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/, //不包含node_modules目录
        use: "babel-loader",  // 使用babel-loader解析js文件,输出能够被浏览器识别的语法
      },
    ],
  },
};

还需要在package.json的script中配置一下start命令,如下

{
 ...,
 "scripts": {
    "start": "webpack --config webpack.config.js"
  },
  ...
}

做了上面这些事情以后,我们在命令行输入

npm start

以后,在目录下生成了dist目录,dist目录下有一个bundle.js,如果我们要在浏览器的控制台看一下打印结果的话,还需要html文件,那么我们就让webpack自动生成以后,自动生成需要使用html-webpack-plugin插件,使用插件的好处是,他会自动引用打包了的js文件

使用html-webpack-plugin插件自动生成html

所以现在我们在创建一个public目录,新建index.html如下

<!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基础篇</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

注意:要写一个id为root的div标签,这样后面才好把内容显示在html上 再在webpack中配置html-webpack-plugin,你看这名字多好记

const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
 ...,
  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],
};

配置文件我们已经配置了,那么现在需要在浏览器上的控制台打印我们的结果,看一下是否输出了ws。


配置devServer自动打开浏览器,修改内容自动刷新页面

现在再看一下打包结果

image.png

已经生成了我们想要的js文件和bundle文件,可是我们还要手动打开index.html,工程化的宗旨就是自动打开,所以我们配置一下webpack.config.js中的devServer就没问题了

const path = require("path");
...

module.exports = {
 ...,
  devServer: {
    static: path.join(__dirname, "./dist"),
    open: true,
    hot: true,
  },
};

目前我们只需要向上面这样配置就可以了,还有一个地方需要改一下,因为devServer是webpack-dev-server的功能,所以我们把package.json中的script改一下,改一下使用webpack-dev-server启动

{
 ...
  "scripts": {
    "start": "webpack-dev-server --config webpack.config.js"
  },
  ...
}

这样子配置以后自动打开浏览器,修改内容自动刷新页面的功能就实现了

实现css文件解析

首先使用npm安装如下css相关依赖

less
css-loader用来解析@import这种语法
style-loader 他是把css插入到head标签中
less-loader 把less转换为css

如果报这个错,证明less版本有点高了

image.png

我的版本如下

 "less": "^3.13.1",
 "less-loader": "^6.2.0",
 "css-loader": "^3.6.0",
 "style-loader": "^1.3.0",
    

接下来我们给自己的程序添加一些样式,在src目录下面新建index.less

#root {
  background-color: red;
  color: white;
  font-size: 50px;
  font-weight: bold;
}

在index.js中进行引入index.less

import App from "./App.js";
import "./index.less";

document.getElementById("root").innerHTML = App.name;

在命令行

npm start

一下,会自动打开浏览器,输出如下

image.png

prefect!!!!这就初步实现了用webpack打包一个能够解析js,css的项目

我们可以在锦上添花一下

开启热更新

为什么需要热更新

热更新这个功能非常非常实用,我们如果不开启热更新,那么我们修改项目,页面也会自动刷新,显示出来我们想要的内容,可是你想想如果你的项目变得超级大,有上万行代码,你就是在你的项目中添加一个console.log,webpack都会重新打包,这是一个非常恐怖的事情,😱,少说他会打包1分钟,我的天,你改个东西,他打包一分钟,你要等一分钟时间,页面才会重新刷新好,展示出效果,这造成了巨大的时间浪费,我们做程序员的,就指着上班时间赶紧完成任务,下班早点回家了,这是在耽误大家的下班时间呀,所以我们一定要拥抱热更新,他会局部的刷新,不刷新整个页面,只变化你修改的部分,提高开发效率,而且我只说了他的其中一个优点,其他优点看下面,爱死他了有没有

热更新有哪些优点

模块热替换HMR - Hot Module Replacement)是 webpack 提供的最有用的功能之一。它允许在运行时替换,添加,删除各种模块,而无需进行完全刷新重新加载整个页面,其思路主要有以下几个方面

1.保留intput的值不用重新输入,弹窗框弹出不用重新打开等
2.只更新改变的内容,以节省开发时间
3.调整样式更加快速,几乎等同于就在浏览器调试器中更改样式

开启热更新步骤

1.在webpack.config.js中添加热更新插件,devServer中开启hot

const webpack = require("webpack"); // 热更新插件是webpack自带的插件
...

module.exports = {
  ...,
  plugins: [
    ...,
    new webpack.HotModuleReplacementPlugin(), // 插件都是类,所以都要使用new
  ],
  devServer: {
   ...,
    hot: true,
  },
};

2.在index.js中配置 if (module && module.hot) { module.hot.accept(); }

import App from "./App.js";
import "./index.less";
// 配置热更新以后,module中会有hot属性,然后我们在执行module.hot中的accept方法通知使用新的模块进行“局部刷新”;
if (module && module.hot) {
  module.hot.accept();
}
document.getElementById("root").innerHTML = App.name;

现在再试试更改App.js中的内容,页面是不是不会刷新,而只是局部刷新。

能够读到这里的同学真是太不容易了,希望大家收获多多,别忘了我们的口号是“驾驭webpack

image.png

下期会讲webpack提升篇:在webpack中添加引用图片功能,设置生产模式和开发模式配置,eslint,typescript等

参考文章