您现在的位置是:首页 >其他 >webpack食用指北网站首页其他

webpack食用指北

法玛梅林 2024-06-17 10:26:16
简介webpack食用指北

何为webpack

wepack即一个模块打包器。它的主要目标是将 JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用。
那么为什么需要把文件打包呢,我的理解是因为在现代web开发中所涉及的资源越来越多,代码越来越复杂,维护和更新都十分的困难,所以才需要webpack来帮助我们管理项目,提升开发效率

webpack前置知识

  1. htmlcssJavaScript
  2. 会用npmyarn或其他包管理工具

webpack项目初始化

我这里使用npm来进行包管理,用yarn或其他也都可以的

npm init -y

在此之后我们就需要安装webpack

npm install webpack webpack-cli -D

或者使用简写

npm i webpack webpack-cli -D

其中webpack-cli为便于我们在命令行键入webpack命令的模块

现在我们在项目中新建一个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>Document</title>
</head>

<body>
    <p>123</p>
    <div id="app"></div>
</body>

</html>

此时我们项目的文件结构如下
文件结构

我们在src目录下新建一个main.js文件

import { sum } from "./js/math"

console.log(111)
console.log(222)
console.log(sum(1, 2))

同时我们在js目录下新建math.js文件

export function sum(num1, num2) {
    return num1 + num2;
}

那么我们项目的初识化就完成了

webpack配置文件

webpack安装完后我们还需要对webpack进行配置,在项目根目录创建一个webpack.config.js的文件

const path = require("path")

module.exports = {
//这里就放着webpack的具体配置
    mode: "development",//为webpack的打包环境,development为开发环境,production为生产环境
    entry: "./src/main.js",//为webpack项目的打包入口,从哪个js文件开始打包
    output: {//为webpack项目的打包出口
        path: path.resolve(__dirname, "./dist"),//把打包好的文件放在哪里
        filename: "bundle.js"//打包好的文件名
    },
}

接下来我们还需要修改package.json
script中加入一行dev

  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "dev": "webpack"
  },

接下来我们在命令行中进入项目文件夹,运行命令

运行webpack

npm run dev

等待打包完成
打包完成
接下来我们需要在index.html中引入bundle.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>Document</title>
</head>

<body>
    <p>123</p>
    <div id="app"></div>
    <script src="./dist/bundle.js"></script>
</body>

</html>

运行index.html,浏览器中查看结果
运行结果
打包成功

loader

其实webpack不仅仅能打包js文件,现代网页所需的资源,例如图片,css,字体文件,vue文件等等其实都可以通过webpack来进行打包。但要知道的是,webpack本身只能打包js文件,想要在webpack中打包其他文件的话需要依赖一种模块,这种模块的名字叫loader

css引入

如果想要打包css文件就需要css-loaderstyle-loader

首先通过npm来安装

npm i css-loader style-loader -D

我们在css文件夹下创建一个style.css文件

p {
    color: red;
}

我们在main.js中引入style.css文件

import "./css/style.css"

然后我们对webpack.config.js进行修改

const path = require("path")

module.exports = {
    mode: "development",
    entry: "./src/main.js",
    output: {
        path: path.resolve(__dirname, "./dist"),
        filename: "bundle.js"
    },
    module: {//对loader的配置都写在这里
        rules: [//rules为一个数组,数组里面是一个个对象,里面存放着不同文件使用什么loader的规则
            {
                test: /.css$/,//test为匹配规则,使用正则表达式
                use: [//use为此文件要使用什么loader,use是一个数组,里面也是一个个对象
                    {
                        loader: "style-loader",//loader为使用什么loader
                        options:{//不是必须的,这里存放这一些此loader的配置信息,比如打包到哪个文件夹,打包的文件名等等
                            
                        }
                    },
                    {
                        loader:"css-loader"
                    }
                ]//注意:use里的loader的执行顺序为从下到上
            }
        ]
    }
}

对loader的配置的几种写法

第一种:

    rules: [
      {
        test: /.css$/, //正则表达式
        // 1.loader的写法(语法糖)适用于只需要一个loader的情况
        loader: "css-loader"
        }
      ]

第二种:

rules: [
   {
        test: /.css$/, //正则表达式
        //适用于需要多个loader但不需要对单独的loader进行配置的情况
        use: [
          "style-loader",
          "css-loader",
          "postcss-loader"
        ]
      },
   	]

最后让我们运行一下看看结果
运行截图
可以看到css已被成功应用

图片引入

图片的引入我们需要file-loaderurl-loader

首先通过npm来安装

npm i file-loader url-loader -D

我们寻找一张图片,并在main.js中引入

import { sum } from "./js/math"
import "./css/style.css"
import bg from "./img/sucai.jpg"
import pic from "./img/nhlt.jpg"

console.log(111)
console.log(222)
console.log(sum(1, 2))

var div = document.createElement("div");
div.style.height = '500px';
div.style.backgroundImage = `url(${bg})`;
var img = document.createElement("img");
img.src = pic;
var app = document.querySelector("#app");
app.appendChild(div);
app.appendChild(img);

接下来我们对webpack.config.js来进行修改

module: {
        rules: [
        //此为之前的配置。。。
            {
                test: /.(jpe?g|png|gif|svg)$/,
                use:[
                    {
                        loader:"url-loader",
                    }
                ]
            }
        ]
    }

让我们运行一下看看
运行截图
图片已被成功显示,但此时的图片是以base64的形式展现的,但大图片转换base64来显示的话会十分占用性能,如果是小图片的话则会节省性能,所以我们需要配置只有图片小于多大的时候才会以base64的形式展现

url的options

我们还是对webpack.config.js文件进行修改

{
      test: /.(jpe?g|png|gif|svg)$/,
      use: [
         {
             loader: "url-loader",
             options: {
                  limit: 100 * 1024//limit即为转换base64的范围,单位是字节,只有小于100*1024字节(100KB)的图片才转换为base64,否则就不转化
             }
          }
      ]
  }

我们再次运行看看结果
运行结果
这回我们可以看到上面的大图片没有转换成base64,而下面的小图片则转换成了base64

文件目录
这时我们发现在dist目录下多出了一个jpg文件,而在我们配置limit之前dist目录是没有出现过jpg文件的,由此我们也可以知道:没有被转换为base64的图片会被打包到我们之前配置好的目录之中

dist目录下的jpg文件名为一串不明所以的字符,在实际开发中我们经常需要把图片放在一个文件夹内,并且每个文件名都要有语义性同时也要有能标识它唯一的标志,那么该怎么写呢

我还是修改webpack.config.js文件

{
     test: /.(jpe?g|png|gif|svg)$/,
     use: [
         {
             loader: "url-loader",
             options: {
                 name: "img/[name]_[hash:6].[ext]",//这里写着文件的命名规则,规则指出文件要存放在img文件夹下,命名为“文件原本的名字”+_+“6位哈希值”+原本后缀名
                 limit: 100 * 1024
             }
         }
     ]
 }

运行之后我们再看文件结构
文件结构
图片成功放进了img文件夹并且也成功改名了,但上次运行时打包的资源依旧还在

自动清除上次打包遗留的资源

webpack可以自动清理上次打包的遗留资源,但初始并不是开启状态
我们可以通过修改webpack.config.js来手动开启它

output: {
        clean: true,//开启自动清理
        path: path.resolve(__dirname, "./dist"),
        filename: "bundle.js"
    },

我们再次运行查看结果
文件结构
这时上次打包所遗留的资源就没有了

资源模块类型

以上的图片打包方式多适用于webpack5以前,在webpack5webpack官方推荐使用asset
webpack5中我们可以使用资源模块类型(asset module type)来替代上面的loaderasset共有四种类型

  1. asset/resource --不管文件大小,直接以文件形式导出
  2. asset/inline --不管文件大小,直接以base64的形式导出
  3. asset/source --导出资源的源代码
  4. asset –webpack自动帮我们决定以什么方式导出

图片的webpack5引入方式

{
     test: /.(jpe?g|png|gif|svg)/,
     type: "asset",//asset的类型
     generator: {
         filename: "img/[name]_[hash:6].[ext]"//导出文件的路径和命名规则
     },
     parser: {
         dataUrlCondition: {
             maxSize: 100 * 1024//类似于limit
          }
     }
 },

字体的webpack5引入方式

字体文件如何引入这里就不再赘述,以下是webpack5中对字体文件的配置

{
   	test: /.(eot|ttf|woff2?)$/,
    type: "asset/resource",
    generator: {
      filename: "font/[name]_[hash:6][ext]",
    },
  },

webpack插件

loader不同的是,loader只能完成一些特定的任务,如特定模块的转换,而插件却能完成更多更广泛的任务,如打包优化,资源管理,接下来将介绍几种开发中常用的插件

html-webpack-plugin

在我们的项目中其实有一个不规范的地方,即我们的html文件是在根目录下的,而最终打包的文件夹中并没有index.html文件,这意味着我们还需要对html文件进行打包,而对html文件打包就用到了这个插件
我们用npm来安装这个插件

npm i html-webpack-plugin -D

安装完了之后我们需要在webpack.config.js里面引入使用

const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = {
    plugins: [
        new HtmlWebpackPlugin()
    ]
}

我们再次运行,此时的dist文件夹下就有了index.html文件了
文件结构
然而这里的index.html和我们根目录下的index.html并不是同一个东西,dist目录里的index.html是由插件中内置的模板生成的,那么如果我们想要使用自己的index.html为模板的话该怎么办呢
我们新建一个public的文件夹并将根目录的index.html放进去
文件结构

修改webpack.config.js

plugins: [
        new HtmlWebpackPlugin({
            template: "./public/index.html"
        })
    ]

做完之后再次打包,此时dist目录下的index.html就是由public文件夹中的index.html打包完成的了

copy-webpack-plugin

这个插件最主要的作用就是将一些不便打包的资源复制到目标文件夹中,比如网站图标
我们一般习惯性的把这些不便打包的资源放入public文件夹中

我们通过npm来安装这个插件

npm i copy-webpack-plugin -D

接下来我们在webpack.config.js中引入插件

const CopyWebpackPlugin = require("copy-webpack-plugin")
plugins: [
        new CopyWebpackPlugin({
            patterns: [//匹配规则,一个数组有多个对象,每个对象都是一个不同的匹配规则
                {
                    from: "public",//从哪个文件夹开始复制
                    to: "./",//复制到那个文件夹,注意:此时的文件目录是从打包文件夹,也就是dist开始的
                    globOptions: {//忽略某个文件不做复制
                        ignore: [
                            "**/index.html"//忽略这个文件夹下的index.html文件
                        ]
                    }
                }
            ]
        }),
    ]

最后我们运行一下就能看到文件复制到dist目录下了

文件结构

Babel

虽然在现代浏览器中,很多的浏览器都支持es6语法,但还有一些老旧浏览器没有支持,为了对那一部分浏览器做适配,我们就需要将es6语法转换为那些浏览器看得懂的语法,这个步骤就由Babel来实现

我们使用npm来安装Babel

npm i @babel/core @babel/cli -D

如果安装了@babel/cli则可以在命令行单独使用babel,我们这里主要是babel和webpack一起使用的情景,单独使用的命令可以参照官方文档

安装完这两个之后babel还并不能使用,我们还需安装其他插件来配合babel运行

@babel/plugin-transform-arrow-functions

这个插件主要是将箭头函数转换为普通函数的

npm i @babel/plugin-transform-arrow-functions -D

@babel/plugin-transform-block-scoping

这个插件主要是将const,let转换为var的

npm i @babel/plugin-transform-block-scoping -D

@babel/preset-env

这个插件相当于是一些常用插件的集合,用了它就不需要再下其他的插件了

npm i @babel/preset-env -D

在webpack中配置babel

我们通过loader的方式来使用babel

下载babel-loader

npm i babel-loader -D

我们修改webpack.config.js文件

{
     test: /.js$/,
     use: {
         loader: "babel-loader",
         options: {
             presets: [
                 "@babel/preset-env"
             ]
         }
     }
 }

再次运行时我们js中的es6语法就会转换成兼容语法了

watch

每当我们修改了文件后想要查看打包效果就要重新打包,而每次打包耗时少则几秒,多则上十秒,严重降低了开发效率,那么有没有一种东西,能在我每次保存时都自动打包,而且降低每次打包的耗时呢

webpack里提供一个叫做watch的功能,打开它之后webpack依赖图中的所有文件只要发生了改变,那么就会重新打包

module.exports = {
    mode: "development",
    watch: true,
    }

这样我们就开启了watch

然后我们手动运行打包一下,以后再对文件进行修改的时候就不用手动再打包了

devtool

有时候,我们代码可能会有写错的地方,当我们打开控制台准备调试时却发现我们的问题被控制台定位到了已经打包好了的一堆完全看不懂的js文件中,这时候如果我们想要知道问题具体出在了源代码的哪一行时我们就需要devtool

module.exports = {
    mode: "development",
    devtool: "source-map",//将我们打包好的js文件和我们的源代码进行一个映射
}

这样devtool就开启了

webpackServer

让资源自动打包的方法不止watch一种,webpack-server也行

首先下载webpack-server

npm i webpack-dev-server -D

watch方法可以实时监听文件的变化,但事实上他无法刷新浏览器,而webpack-server却可以
我们在package.json中增加一行

"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "dev": "webpack",
    "server": "webpack serve"//npm run server 就是启动webpack-server
  },

接下来我们修改webpack.config.js文件

module.exports = {
    mode: "development",
    devtool: "source-map",
    devServer: {
         static: {
            directory: path.join(__dirname, './public'),//如果webpack需要某些文件但src目录下找不到就回来这个目录找,如index.html和favicon.ico
        },
        host: "0.0.0.0",//设定服务器的本地IP地址
        port: 7777,//设置服务器的端口号
        open: true,//是否在打包完成后自动开启浏览器
        compress: true,//是否以gzip格式压缩资源来提升传输性能
    },
 }

注意:staticwebpack5新语法,在webpack5以前如果想实现这种功能则要

devServer: {
		contentBase: "./public",//webpack5以前的写法,现在使用webpack5对其进行打包的话会报错并推荐你使用上面那种写法
        host: "0.0.0.0",//设定服务器的本地IP地址
        port: 7777,//设置服务器的端口号
        open: true,//是否在打包完成后自动开启浏览器
        compress: true,//是否以gzip格式压缩资源来提升传输性能
    },

运行npm i server 就能看到此时浏览器运行成功
运行截图

控制塔截图

热替换

无论是watch还是webpack-server,他们只要检测到了一个模块的修改,就会对这个项目重新打包并且刷新整个页面,但我其实只对其中一个模块进行了更改,其他模块我还想保存它的运行状态的话该怎么做呢

热替换能在应用程序运行中替换,添加,删除模块而不需要刷新整个页面
webpack-server本身就支持模块热替换功能,我们只需开启就好。

devServer: {
        static: {
            directory: path.join(__dirname, './public'),
        },
        hot: true,//开启热替换功能
        host: "0.0.0.0",
        port: 7777,
        open: true,
        compress: true,
    },

此时虽然开启了热替换,但webpack并不知道哪些模块需要进行热替换,这些模块还需要我们进行配置

我们在main.js中添加这么一段代码

if (module.hot) {
    module.hot.accept("./js/math.js", () => {//第一个参数为哪个模块需要进行热替换,第二个参数为回调函数,他会在模块发生热替换之后运行
        console.log("math.js模块更新了")
    })
}

接下来我们再运行npm run server并尝试修改math.js并回到浏览器查看结果

config的分离

随着我们配置越写越多,配置文件阅读起来也越来越麻烦,而且生产环境和开发环境所以来的配置也不同,所以我们就需要对目前的一个配置文件进行分割
分割配置文件我们需要一个插件 webpack-merge

npm i webpack-merge -D

接下来我们在根目录新建一个config文件夹,里面新建三个js文件
文件结构
我们将原本的配置文件复制到这三个文件中
webpack.comm.config.js为公共配置文件,无论是开发环境还是生产环境都需要的
webpack.dev.config.js为开发环境配置文件
webpack.prod.config.js为生产环境配置文件

接下来我们需要对这三个文件进行删减,比如公共文件就放公共部分,开发文件就放开发部分,生产部分就放生产部分

分完之后我们需要在webpack.dev.config.jswebpack.prod.config.js中引入webpack.comm.config.js文件

dev

const { merge } = require('webpack-merge')
const commonConfig = require("./webpack.comm.config")
module.exports = merge(commonConfig, {
		//配置...
})

prod

const { merge } = require("webpack-merge")
const commonConfig = require("./webpack.comm.config")
module.exports = merge(commonConfig, {
    //配置...
})

之后我们还需要在package.json中修改script

"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "dev": "webpack --config ./config/webpack.dev.config.js",
    "server": "webpack serve --config ./config/webpack.dev.config.js",
    "build": "webpack --config ./config/webpack.prod.config.js"
  },//--config为使用什么config文件

之后一切就做完了

结语

第二篇博客,感觉还是有些不够清楚的,有些知识点也没写出来,可能以后还会再写一篇关于webpack的博客当做这篇博客的补充吧
非常感谢能看到这里,最后,还是希望我们变得更强:)

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。