• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

初识webpack

武飞扬头像
孤独的根号_
帮助34

说下起因吧,最近正准备学习一下vite,所以特意补充一下前置知识~

基本概念

我们知道当我们开发完成一个网站后,文件很多,体积很大,网页加载缓慢,应该如何缩小网站代码的体积呢?

我们也不可能手动去合并所有的文件并分析哪些是有用的哪些是没有用的,所以就诞生了自动化的打包工具---webpack!

webpack是一个静态模块打包工具,作用是分析 、压缩、打包代码。 webpack中文官网

webpack会帮我们把图中左边所有文件之间的相互依赖关系进行分析,然后进行压缩,最后打包成静态资源。

  • 支持所有类型文件的打包
  • 支持less/sass => css
  • 支持ES6/7/8 => ES5
  • 压缩代码,提高加载速度

开始介绍之前我们必须要先理解一些核心概念:

  • 入口(entry)
  • 出口(output)
  • loader
  • 插件(plugin)

入口指的是webpack应该使用哪个模块开始进行打包,并作为构建其内部依赖图的开始,进入入口文件后,webpack会找出该文件引入的一些其他文件,也就是我们所说的依赖(直接和间接)然后开始构建依赖关系图。默认会去找./src/index.js,但是我们可以在项目根目录新建一个webpack.config.js的文件来改变这个入口文件,例如:

module.exports={
    entry:"./path/to/my/entry/file.js"
}

依赖图:每当一个文件依赖另一个文件时,webpack都会将文件视为直接存在依赖关系。这使得webpack可以获取非代码资源,如image或web字体等。并会把它们作为依赖提供给应用程序。

出口指的是我们需要告诉webpack在哪里输出它所创建的bundle,以及如何命名这些文件。默认输出的路径为./dist/main.js,其他生成文件默认放置在./dist文件夹中。

可以通过在配置中制定一个output字段,来配置这些处理过程:

const path=require('path');

module.exports={
    entry:'./path/to/my/entry/file.js',
    output:{
        path:path.resolve(__dirname,'dist'),
        filename:'my-first-webpack-bundle.js'
    }
}

在上面的示例中,我们通过 output.filename 和 output.path 属性,来告诉 webpack bundle 的名称,以及我们想要 bundle 生成到哪里。

loader webpack只能理解JavaScript和JSON文件,这是webpack开箱可用的自带能力。loaderwebpack能够去处理其他类型的文件,并将它们转换为有效模块以供引用程序使用,以及被添加到依赖图中。 loader有两个属性:

  1. test属性,识别出哪些文件会被转换。
  2. use属性,定义出在进行转换时,应该使用哪个loader。
const path=require('path');

module.exports={
    module:{
        rules:[{test:/\.txt$/,use:'raw-loader'}]
    }
    
}

这就告诉 webpack 编译器(compiler) 如下信息:

插件可以用于执行范围更广的任务,包括:打包优化、资源管理、出入环境变量。想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};

在上面的示例中,html-webpack-plugin 为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中。

开始打包之前我们先配置一下环境:

首先先在本地创建一个名为webpack-study的文件夹,在终端中输入npm init -ynpm init(前者可以一键生成package.json文件,后者需要手动输入相关信息,一般使用前者就可以),会生成一个包含这个创建项目信息的json文件。

既然要用webpack打包当然需要先安装了,通过使用npm i webpack webpack-cli -D命令安装webpack以及脚手架(也可用yarn),再用vscode将当前文件夹打开:

接下来我们需要在scripts脚本中配置我们自己的打包命令:

"scripts":{
    "build":"webpack" // key可以自定义~
}

打包js文件

当前目录下创建src文件夹、index.js、count文件夹以及count.js文件

在count.js中导出一个求和的函数:

export function sum(a,b){
    return a b;
}

在index.js文件中引入

//index.js(入口文件)
imoprt {sum} from './count/count.js';

console.log(sum(1,2))

执行npm run build命令进行打包后会在当前目录生成dist文件夹下面的main.js

终端运行这个文件后会打印出3

如果想要修改入口文件和出口文件的话可以在当前目录下新建一个webpack.config.js文件

const path=require("path");

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

这里深入一下,执行npm run build命令之后会经历一个这样的流程:

  1. 先从package.json中找到我们自定义的脚本命令,然后执行后面真正的打包命令
  2. 有没有进行自定义配置(webpack.config.js文件)没有的话进行默认配置文件,有的话则根据配置文件获取配置参数
  3. 找到入口文件及其内部的一些依赖文件,先构建出依赖关系图,然后对各个模块文件进行编译
  4. 最终输出到指定文件

生成html文件

下面我们先来做一个小案例---jquery隔行变色

首先安装一下 npm i jquery 然后我们在入口文件(main.js)中

import $ from 'juqery';

$("ul li:even").css("background","red")
$("ul li:odd").css("background","blue")

最后在当前目录下新建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>Document</title>
</head>
<body>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <li>9</li>
        <li>10</li>
    </ul>
</body>
</html>

那怎么让这两个文件产生关联呢?这就是我们接下来要说的html-webpack-plugin插件

执行npm i html-webpack-plugin -D命令并在webpack.config.js文件中增加plugins选项:

const path=require("path");
const HtmlWebpackPlugins = require("html-webpack-plugin");  // 引入插件

module.exports={
    entry:"./src/main.js",
    output:{
        path:path.resolve(__dirname,'dist'),
        filename:"bundle.js" 
    },
    plugins:[
        new HtmlWebpackPlugins({
            template:"./public/index.html" // 要生成的html文件
        })
    ]
}

重新执行npm run build命令后dist文件夹终会出现index.html,打开会发现

webpack会帮我们把这些文件进行关联:(下图为打包后的index.html文件)

打包css文件

我们依然需要先在当前目录下新建css文件夹下的index.css文件,并且执行npm i css-loader style-loader -D命令,因为webpack并不认识css文件,然后在index.css文件中给所有li标签去除前面的点:

li{
    list-style:none;
}

webpack中也需要增对应的loader:

const path=require("path");
const HtmlWebpackPlugins = require("html-webpack-plugin");  // 引入插件

module.exports={
    entry:"./src/main.js",
    output:{
        path:path.resolve(__dirname,'dist'),
        filename:"bundle.js" 
    },
    plugins:[
        new HtmlWebpackPlugins({
            template:"./public/index.html" // 要生成的html文件
        })
    ],
     module: {
        rules: [
            {
                // 匹配到以css结尾的文件使用css-loader和style-loader加载
                test:/\.css$/i,
                use:["style-loader","css-loader"] 
            },
            // 以下为less文件的loader
            {
                test:/\.less$/i,
                use:['style-loader','css-loader','less-loader']
            }
        ],
  },
}

里面需要注意的是use:["style-loader","css-loader"] 是这个地方,这里是有书写顺序的,链会逆序执行,第一个loader将其结果(被转换后的资源)传递给下一个loader,css-loader是用来识别css语法的,style-loader会生成style标签并对css进行外链。

打包图片

我们再给li标签设置一个背景图片

li{
    list-style:none;
    background: url('../../public/xing.png');
}

同时在入口文件main.js文件通过js在页面上添加一张图片

import './css/index.css'
import './less/index1.less'

import img from '../public/superman.jpg'
const dom =document.createElement("img")
dom.src=img
document.body.appendChild(dom)

webpack.config.js文件也需要增加上对图片格式的匹配

const path=require("path");
const HtmlWebpackPlugins = require("html-webpack-plugin");  // 引入插件

module.exports={
    entry:"./src/main.js",
    output:{
        path:path.resolve(__dirname,'dist'),
        filename:"bundle.js" 
    },
    plugins:[
        new HtmlWebpackPlugins({
            template:"./public/index.html" // 要生成的html文件
        })
    ],
     module: {
        rules: [
            {
                // 匹配到以css结尾的文件使用css-loader和style-loader加载
                test:/\.css$/i,
                use:["style-loader","css-loader"] 
            },
            // 以下为less文件的loader
            {
                test:/\.less$/i,
                use:['style-loader','css-loader','less-loader']
            },
            {
                test:/\.png|jpg|gif/,
                type:"asset"
            }
        ],
  },
}

最后执行npm run build命令

最终会在页面中展示出来,但是我们会发现在dist文件夹中只有那张大图,没有li标签的背景图,这是因为webpack在处理图片的时候当图片<8kb时会转base64字符串,>8kb的时候会复制该文件,base64又有什么优点呢?

避免多次发起请求,方便传输,原来是一张图片和css,客户端需要发起两次请求,转为base64相当于把图片合并到了css文件里

为什么webpack只对小的图片进行base64转换呢?因为大的图片在进行完base64转换后体积会增大!

打包font字体图标

webpack默认是会自动打包字体图标的,不需要做任何的配置,然后将其输出到构建目录。

把font文件夹放到public文件夹下:

然后我们在入口文件中引入:

// ...
import '../public/font/iconfont.css'

const div = document.createElement("div");
div.className = "iconfont icon-shouye"
document.body.appendChild(div)

直接运行npm run build命令会发现:

并且文件名称为了避免打包后文件名称重复造成的覆盖问题使用了hash算法随机生成来保证每个文件的唯一性,随着项目中的字体图标文件越来越多管理起来变得不太方便,为此我们也可以在webpack.config.json文件中进行配置来达到分类的效果:

const path=require("path");
const HtmlWebpackPlugins = require("html-webpack-plugin");  // 引入插件

module.exports={
    entry:"./src/main.js",
    output:{
        path:path.resolve(__dirname,'dist'),
        filename:"bundle.js" 
    },
    plugins:[
        new HtmlWebpackPlugins({
            template:"./public/index.html" // 要生成的html文件
        })
    ],
     module: {
        rules: [
            {
                // 匹配到以css结尾的文件使用css-loader和style-loader加载
                test:/\.css$/i,
                use:["style-loader","css-loader"] 
            },
            // 以下为less文件的loader
            {
                test:/\.less$/i,
                use:['style-loader','css-loader','less-loader']
            },
            {
                test:/\.png|jpg|gif/,
                type:"asset",
                //此处也可以写generator
                // ...
            },
            {
                test:/\.(eot|svg|ttf|woff|woff2)$/i,
                type:"asset/resource" //assets/resource表示不转成base64,直接复制到dist
                generator:{ // 生成器 自动输出到指定的位置和文件中
                        // 内置变量 [name] 表示之前叫什么名字就原样输出,也就是原文件名
                        // [ext]原来的后缀名,包括. 例如.eot
                       filename:"fonts/[name][ext]"
                }
            }
        ],
  },
}

重新打包后:

这时候文件名有重复的,我们可以加上一点hash:

...
{
    ...
    filename:"fonts/[name]--[hash:6][ext]" // 表示文件名称跟hash值用--连接,hash值随机生成六位 
}

此时:

处理语法降级

现在的浏览器依然不支持一些比较高级的语法像ES6、ES7,但是我们在开发中却经常使用这些高级语法,所以我们需要babel来进行一个降级。

babel是一个独立的工具,类似于less,所以我们需要安装babel(核心包,js编译器,用来分析代码) 、babel-loader(webpack翻译js代码)的包,还有一个预设包babel-preset-env(降级规则,转什么语法)

执行npm install -D babel-loader @babel/core @babel/preset-env命令,然后在webpack.config.js中添加配置:

// ...
module: {
  rules: [
    {
      test: /\.js$/, // 匹配.js的文件
      exclude: /(node_modules|bower_components)/, // 排除不对node_modules和bower_components下的文件进行降级,因为这些都是别人已经打包好的,不需要重复进行打包
      use: {  // 数组:使用默认配置  对象:使用预设
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env']
        }
      }
    }
  ]
}

开始测试,首先在main.js中写一个箭头函数,注意不要去执行,因为一旦执行webpack为了压缩代码会直接把里面的结果进行打包,这样我们就看不出降级的效果了

// main.js
const fn=()=>{
    console.log("我是一个箭头函数")
}
console.log(fn)

执行打包命令后查看dist中的文件

可以看到箭头函数已经被转换为了普通函数。

搭建webpack服务器

因为每次我们写完代码都需要重新打包,浪费宝贵的开发时间。当我们遇到比较大的项目时修改代码重新打包时,非常耗时,这是因为重新打包需要:

  1. 再次找到入口并开始构建依赖关系图
  2. 从磁盘中读取对应的文件到内存中(比较耗时)
  3. webpack用配置好的loader和plugins翻译和处理文件(css?js==》css-loader、style-loader)
  4. 再将处理后的内容写入到磁盘出口位置(比较耗时)

代码再变化,重复上述操作

所以我们可以使用webpack搭建一个本地服务器来实现代码修改后页面就可以自动发生改变,以此来提高我们的开发效率

首先需要先安装npm i webpack-dev-server -D,然后自定义webpack开发服务器启动命令在package.json里

 "scripts": {
    "build": "webpack",
    "serve":"webpack serve"
  },

最后执行npm run serve就可以直接在浏览器中查看效果

对比上面的四步,执行npm run serve的时候共做了以下几件事:

  1. 找到入口并开始构建依赖关系图
  2. 磁盘读取对应文件到内存中
  3. webpack用配置好的loader和plugins翻译和处理文件
  4. 再将处理后的内容放到内存
  5. 代码再变化只重新打包变化的代码,自动更新到页面无需手动刷新
打包后直接在浏览器中打开时会有这样的提示,意思是:“mode这个选项没有设置,将会用production作为默认值”
module.exports={
    // 模式,取值范围:production/development
    // webpack把打包分为了两种模式,一种是线上生产环境,另一种是开发环境
    // production:生产环境,会对代码进行压缩混淆
    // development:开发环境,不会对代码进行压缩混淆,速度快,节省了打包时间
    mode:"development" // 上线用production
}

每次修改webpack.config.js文件都需要重新进行启动配置才会生效,再次执行npm run serve发现已经没有提示了,并且在修改了代码之后页面会立即被更新,这种修改代码后不用刷新浏览器就直接修改页面的技术叫做“代码热更新(Hot Module Replacement)”,就是只打包修改了的部分然后以打补丁的形式替换到浏览器上,开发效率非常高!

下面再说一些webpack-dev-serve的一些其他配置

module.exports={
    devServe:{
        prot:3000, // 自定义端口号
        open:true // 是否自动打开浏览器
    }
}

接下来如果项目需要上线的话,需要先修改mode选项为production环境并且运行npm run build命令得到dist文件夹,然后把这个文件夹压缩发送给后端部署即可。

end...

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanfekbj
系列文章
更多 icon
同类精品
更多 icon
继续加载