likes
comments
collection
share

一张图带你了解webpack基础

作者站长头像
站长
· 阅读数 86

前言

什么是webpack?

概念:本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器 。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图 ,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。 它包括三个模式:

  • 生产模式 production
  • 开发(测试)环境 development
  • none

从处理资源来说,webpack就是一个bundler(打包工具)。 很多人可能会问,打包和上述图片有什么关系呢?这就得介绍webpack中另外一个重要的东西 ---loader,相信了解过webpack官网的小伙伴都知道,loader是用于对模块的源代码进行转换。简单来说就是在开发中我们不仅仅有基本的js代码处理,我们也需要加载css、图片,也包括 一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scssless转成css,将.jsx.vue文件转成js文件等等。而webpack本身是不支持对这些模块直接进行转化的,这时候就需要用到扩展的loader就可以完成转化了。在不同的模块中,webpack-loader也是不同的,它使用了单一设计模式,一个loader就做一件事。以下是常见的loader:

  • babel-loader:对js进行转译,把es6转换成es5
  • css-loader:加载css,支持模块化、压缩、文件导入等
  • file-loader:把文件输入到一个文件夹里,在代码中通过相对Url去引入输出的文件
  • url-loader:加载远程资源,以base64的方式把文件内容注入代码中
  • awesome-typescript-loader:将ts转化为js,再通过babel转化为es5
  • image-loader:加载并压缩图片文件
  • 想要了解更多关于loader的可以去看看babel官方文档

webpack基本概念

  • context 上下文 基础目录,绝对路径,用于从配置中解析入口起点(entry point)和 loader 示例:
// 当前目录的物理路径
const basePath = __dirname;
context: path.join(basePath,"src")
  • resolve 解析 这些选项能设置模块如何被解析 示例:
resolve: {
    // extensions 检测以这些后缀的文件,处理文件
    extensions: [".js", ".ts", "tsx"...等] 
}
  • entry 入口 入口起点指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始的。 示例:
// 入口文件
entry: ["./index.html"...等]
// 入口文件可能不止一个
entry: {
    // app  vender  打包文件后取别名
    app: ["./index.js"],
    vender: ["./index.ts"]...等
}
  • output 输出 配置 output 选项可以控制 webpack 如何向硬盘写入编译文件。 示例:
// 出口,打包文件到xxx目录下
const path = ruquire("path");
output: {
    path: path.join(basePath, "dist"),
    filename: "bundle.js"
}
  • module 模块 在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为模块。 示例:
module: {
    // rules给resolve里的后缀添加规则
    rules: [
        // 使用正则, \.表示转译
        test: /\.js$/,
        // 转译哪种文件使用相对应的loader
        loader: "babel-loader"
    ]
}
  • plugins 插件 插件是 webpack 的支柱功能。webpack 自身也是构建于,你在 webpack 配置中用到的相同的插件系统之上! 插件目的在于解决 loader 无法实现的其他事。 示例:
const HtmlWebpackPlugin = ruquire("html-webpack-plugin");
plugins: [
    new HtmlWebpackPlugin({
        filename: "index.html",
        template: "index.html"
    })
]

看完这些基础概念之后,相信小伙伴们都对webpack有很大的兴趣,想要手撸一个试试手了。下面是我写的一个简单例子,感兴趣的小伙伴可以去尝试一下。

一个小demo

新建一个webpack-demo文件夹 文件初始化

  • npm init -y

在webpack-demo根目录下新建src文件夹,添加三个文件,代码如下:

// 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 class="container">
        <div class="root"></div>
    </div>
</body>
</html>
// index.jsx
import * as React from "react";
import * as ReactDOM from "react-dom";
import Hello from "./hello";

ReactDOM.render(
    <Hello />,
    document.getElementById('root')
)
// hello.jsx
import * as react from 'react';
import * as ReactDOM from 'react-dom'

const Hello = () => {
    return (
        <div>
            Hello webpack!
        </div>
    )
}

export default Hello

接下来的操作相信大家都猜到了,没错,就是配置webpack。 首先,我们在webpack-demo根目录下新建两个文件。

  • .babelrc
  • webpack.config.js

很多小伙伴可能会疑惑,配置webpack为什么要.babelrc文件啊?在这里就需要解释一下babel是一种转译的配置工具,分为三个阶段。

  • parsing
  • transfroming
  • generating

举个简单的小栗子: 以es6转译为es5代码为例

// .babelrc
{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ]
}

下面就是配置webpack的主要内容了,在项目根目录下新建webpack.config.js文件。具体代码如下:

const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin')
const basePath = __dirname;  // 当前项目的物理路径
// console.log(path.join(basePath),'......');

module.exports = {
    // 上下文
    context: path.join(basePath, "src"),
    // 解析
    resolve: {
        // extensions 检测以.js为后缀的文件,处理文件
        extensions: [".js", ".jsx"]
    },
    // 入口
    entry: ["./index.jsx"],
    // 出口,打包文件到dist目录下
    output: {
        path: path.join(basePath, "dist")
    },
    // 模块,找到规则
    module: {
        // 给resolve里的后缀添加规则
        rules: [
            {
                // 正则 \. 表示转义,括号里面表示两者都行
                test: /\.(js|jsx)$/,
                // 需要使用哪种loader
                loader: "babel-loader"
            }
        ]
    },
    // 插件
    plugins: [
        new HtmlWebpackPlugin({
            filename: "index.html",
            template: "index.html"
        })
    ]
}

配置完webpack.config.js文件之后,很多小伙伴发现在终端下面运行会报一系列的错误。那是因为我们的package.json文件还没有配置完成。具体的配置代码如下:

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server --mode=development --hot --open",
    "build": "webpack --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/cli": "^7.17.6",
    "@babel/core": "^7.17.9",
    "@babel/preset-env": "^7.16.11",
    "@babel/preset-react": "^7.16.7",
    "babel-loader": "^8.2.4",
    "html-webpack-plugin": "^5.5.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "webpack": "^5.72.0",
    "webpack-cli": "^4.9.2",
    "webpack-dev-server": "^4.8.1"
    "clean-webpack-plugin": "^4.0.0"
  }
}

这里主要是修改了package.json中的script脚本以及需要安装的一些依赖包。

  • scripts

"start": "webpack-dev-server --mode=development --hot --open"含义:start用于项目的初始化,是接下来一切工作的依赖起始端;webpack-dev-server 是为静态文件提供服务;--mode=development表示生产环境;--hot --open表示自动刷新和热替换。"build": "webpack --mode=development"表示打包时需要的脚本配置。

  • dependencies

@babel/cli,@babel/core,@babel/preset-env等表示该本次测试需要的一些依赖包,后面对应的是其安装的版本。我们可以把这些需要安装的依赖包直接粘贴,再直接在终端中npm i(yarn也是一样)下载依赖包,或者在终端中直接一个一个安装一下这些依赖包(有些版本更新或会有些许配置不同)

配置完这些文件,我们在终端中执行 npm run start 就可以在页面上看到hello.jsx上的内容渲染到了index.html页面上。效果如下:

一张图带你了解webpack基础 还可以在终端中执行 npm run build将整个项目打包到dist目录下面。这一整套流程下来,一个基本的webpack项目配置就完成了。

优化

相信细心的小伙伴在执行 npm run build 的时候会发现,运行完后除了生成一个dist目录外,在终端中还会有compiled successfully in xxx ms这里表示的是使用webpack打包完成后需要多少时间。

一张图带你了解webpack基础

看起来只是0.2s左右,如果是一个超大型的项目要打包,时间方面是不是的让我们难以接受?

这也是webpack配置中需要优化的知识点了。由于本demo是打算构建react项目,在webpack.config.js文件中我们可以稍加修改。

  • entry
entry: {
        app: ['./index.jsx'],  // app 取别名
        vender: [
            'react',
            'react-dom'
        ]
    },

把react中的一些公有依赖包打包在同一个文件,之后更新会缓存,再一次打包不会改变,不会出现304情况。

  • output
output: {
    path: path.join(basePath, "dist"),
    filename:"[name].[chunkhash].js"
}

[name]表示变量名占位;[chunkhash] 哈希值,每次打包名字都不一样 生成每个不同的文件,所以请求不止一次,会缓存,如果代码没有更新,下次不用再次发送请求。

  • module
module: {
        rules: [
            {
                test: /\.js$/,
                // 排除 node_modules 优化
                exclude: /node_modules/,
                loader: 'babel-loader'
            }
        ]
    },

在rules中添加exclude,排除 node-modules不打包,减少不必要代码

  • plugins
plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            filename: "index.html",
            template: "index.html"
        })
    ]

添加clean-webpack-plugin依赖包,打包时会把上一次的目录删除,清理每次打包下没有使用的目录

添加完这些之后,我们在来看一下效果。

一张图带你了解webpack基础 比之前打包速度快了0.05s左右,当然,由于本demo代码量,并且每位小伙伴电脑设备配置不一,可能在调试上面结果会稍有误差,这都不是重点!重点是要了解如何优化。优化后代码如下:

const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const basePath = __dirname;  // 当前项目的物理路径
// console.log(path.join(basePath),'......');

module.exports = {
    // 上下文
    context: path.join(basePath, "src"),
    // 解析
    resolve: {
        // extensions 检测以.js为后缀的文件,处理文件
        extensions: [".js", ".jsx"]
    },
    // 入口
    entry: {
        app: ['./index.jsx'],  // app 取别名
        vender: [
            'react',
            'react-dom'
        ]
    },
    // 出口,打包文件到dist目录下
    output: {
        path: path.join(basePath, "dist"),
        filename: "[name].[chunkhash].js"
    },
    // 模块,找到规则
    module: {
        // 给resolve里的后缀添加规则
        rules: [
            {
                // 正则 \. 表示转义,括号里面表示两者都行
                test: /\.(js|jsx)$/,
                // 需要使用哪种loader
                loader: "babel-loader",
                // 排除node_modules 不打包
                exclude: /node_modules/,
            }
        ]
    },
    // 插件
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            filename: "index.html",
            template: "index.html"
        })
    ]
}

总结

希望本文对各位小伙伴能有所帮助。如果有不足之处希望批评指正。喜欢这篇文章的小伙伴可以点赞+收藏哦。参考文献:

一张图带你了解webpack基础

转载自:https://juejin.cn/post/7088970247184580638
评论
请登录