webpack+vite前端构建工具 -6从loader本质看各种语言处理 & 7webpack处理html

发布于:2025-06-23 ⋅ 阅读:(14) ⋅ 点赞:(0)

6 从loader本质看各种语言处理

语法糖?

6.1 loader的本质

  • loader本质是一个方法,接收要处理的资源的内容,处理完毕后给出内容,作为打包结果。

    所有的loader(例如babel-loader, url-loader等)export出一个方法。注册loader去处理某种类型文件。

6.1.1 手搓一个loader

1 定义loader
// mycss-loader\index.js
module.exports = function (cssContent) {
    console.log("🚀 ~ cssContent:", cssContent);
    // 将0变为0px
    cssContent = cssContent.replace("0", "0px");
    return cssContent;
}
2 注册loader
// webpack.config.js
module.exports = {
    mode: "production", //webpack4以后要指定mode
    // loader
    module: {
        rules: [
            {
                test: /\.css/,
                use: [minicss.loader, "css-loader", "./mycss-loader"]
            },
        ]
    }
}

最先调用mycss-loader.
注意路径,mycss-loader在当前目录下。

3 打包

打包出来的css文件里的padding,变为0px。
在这里插入图片描述

6.1.2 loader本质

  • 从手搓的mycss-loader可以推测babe-loader

    • 【babel-loader编译】通过babel-loader编译js,即babel-loader函数接收js文件内容,对es6字符串编译为es5字符串等等。
  • 同理,编译ts, jsx都是这样,目标都是转换为js.

  • 基本上各种语言处理可以看做

    1. 为改语言编写loader
    2. 编写loader配置

6.2 ts编译打包

6.2.1 安装ts的编译loader和编译库

命令:npm install typescript ts-loader --save-dev

6.2.2 定义编译规则

ts规则较多,可以集成到单独的文件tsconfig.json里。

// webpack.config.js
module.exports = {
	mode: "development", //webpack4以后要指定mode
    // loader
    module: {
        rules: [
            {
                test: /\.tsx?$/,//匹配ts,tsx文件
                use: {
                    loader: 'ts-loader'
                }
            }
        ]
    }
}
// tsconfig.json
// 暂时为空

定义ts文件

// ts1.ts
let a: number = 123;
console.log("🚀 ~ a:", a);

在app.js里引入ts1.ts

// app.js
import b from './a.js'
import "./test.css"
import img1 from "./img/两狗对视.jpg"
import './ts1.ts';
new Image().src = img1;
(() => {
    let a = 23;
    console.log(b);
    console.log(a);
})()

6.2.3 打包

ts语言在打包文件里编译为js语言
在这里插入图片描述

6.3 规律总结

项目里所有的loader都是如此。面对新的loader,要学会如何使用,只需要查一下相关配置即可。
记义不记形。

7 webpack处理html

前面介绍了webpack处理js、css等,还剩下html。
一个项目在浏览器展示,先拿到html文件。

  • 项目的3要素
    • html
    • js
    • css
浏览器 html js 执行js,创建内容
css 执行css渲染样式

解读:先拿到项目的html,然后html加载js和css。加载js后执行js,创建内容。加载css后执行css,渲染页面样式。
html是起点。

  • 需要html做什么
    • 提供html模版,复用固定内容
    • 打包时生成一个html
    • 打包的html自动引入打包后的js, css

7.1 示例

7.1.0 html文件

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>webpackhtml</title>
</head>

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

</html>

快捷键: !

7.1.1 安装plugin

  • 使用插件处理html而非loader
  • 为什么不用loader
    • loader本质:webpack只能识别js,让webpack识别引入的其他文件需要用loader
    • 但html不需要webpack识别,而是作为载体去承载打包后的js文件
    • 因此webpack不需要识别html,只是用html承接weboack处理的结果(几乎不可能需要在js文件里import html文件)
    • 因此不使用loader处理html
  • 需要做什么
    • 拿到html模板,将打包后的内容加入到html文件中

    因此不是处理html,而是使用html去处理打包结果

安装命令:npm install html-webpack-plugin --save-dev

7.1.2 引入plugin

// webpack.config.js
const htmlwebpack = require('html-webpack-plugin');

7.1.3 注册plugin

// webpack.config.js
const htmlwebpack = require('html-webpack-plugin');
module.exports = {
    plugins: [
        new htmlwebpack({
            template: './index.html',// 写法1,指定html模板
            // templateContent: function () {  // 写法2,自定义模板,使用频率较低
            //     return '<div>123</div>'
            // }
            filename: "index.html"
        })
    ]
}

7.1.4 打包

打包结果
在这里插入图片描述
打包后的html
可以看到引入了打包后的js和css文件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>webpackhtml</title>
<script defer src="app1.34fb.bundle.js"></script><link href="test.bundle.css" rel="stylesheet"></head>

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

</html>

如果mode为production,打包后的index.html会压缩为一行代码

7.2 多入口情况

  • 传统vue项目是单入口(单页面项目)。
    • vue项目中页面的切换,本质还是同一个页面,只是执行不同的js创建不同的内容
  • 多入口,即多个页面,用于多个html的情况。切换页面时是切到另外一个html文件。
    • 多入口,表示多个js文件。

下面给出多入口处理的示例

7.2.0 多入口html文件

在原来基础上加入一个app2.js.

// app2.js
console.log("app2.js")

7.2.1 多入口文件打包配置

webpack.config.js的entry添加app2.js.

// webpack.config.js
const htmlwebpack = require('html-webpack-plugin');
module.exports = {
    // entry: "./app.js",//单入口写法,入口指定为app.js
    entry: {  // 多入口写法:入口名称+入口文件
        app1: ["./app.js"],
        app2: './app2.js'
    },
    // entry: ["./app.js", './app2.js'] // 两个文件同时作为一个入口
    output: {
        path: __dirname + '/dist', // 绝对路径,__dirname是node的全局变量,表示当前目录的绝对路径
        filename: "[name].[hash:4].bundle.js", //将name加到filename里,打包结果文件是app.bundle.js和app2.bundle.js,hash是对文件是否有改变的标志,:4表示截取前4位
    },
    mode: "production", //webpack4以后要指定mode
    // loader
    module: {
        rules: [
        ]
    },
    plugins: [
        new htmlwebpack({
            template: './index.html',// 写法1,指定html模板
            // templateContent: function () {  // 写法2,自定义模板,使用频率较低
            //     return '<div>123</div>'
            // }
            filename: "index.html"
        })
    ]
}

7.2.2 打包

1 打包结果

打包结果包含两个js文件。
在这里插入图片描述
两个js文件在html如何加载呢
——都加到index.html里。

在这里插入图片描述

2 问题
  • 多入口意味着多个html,每个入口js应该有自己的html。
  • 正确逻辑:每个打包的js文件都应该有专属的html,html只引入一个js文件,而不是一个html文件引入2个js文件。
  • 正确做法:再new一个html-webpack-plugin插件

app2.js的html模板可以是之前的index.html,也可以指定新的,例如index2.html.

3 正确配置并打包

index2.html就不赘述了,与index.html一样的。

  • webpack.config.js的plugin再加一个plugin,用于给app2.js指定html模板,即index2.html.
  • 注意还加了chunks属性,注意chunks的值要与entry的key对应。
// webpack.config.js
const htmlwebpack = require('html-webpack-plugin');
module.exports = {
    // entry: "./app.js",//单入口写法,入口指定为app.js
    entry: {  // 多入口写法:入口名称+入口文件
        app1: ["./app.js"],
        app2: './app2.js'
    },
    // entry: ["./app.js", './app2.js'] // 两个文件同时作为一个入口
    output: {
        path: __dirname + '/dist', // 绝对路径,__dirname是node的全局变量,表示当前目录的绝对路径
        filename: "[name].[hash:4].bundle.js", //将name加到filename里,打包结果文件是app.bundle.js和app2.bundle.js,hash是对文件是否有改变的标志,:4表示截取前4位
    },
    mode: "production", //webpack4以后要指定mode
    // loader
    module: {
        rules: [
        ]
    },
    plugins: [
        new htmlwebpack({
            template: './index.html',// 写法1,指定html模板
            // templateContent: function () {  // 写法2,自定义模板,使用频率较低
            //     return '<div>123</div>'
            // }
            filename: "index.html",
            chunks: ["app1"]
        }),
        new htmlwebpack({
            template: './index2.html',
            filename: "index2.html",
            chunks: ["app2"]
        })
    ]
}

打包完成,可以看到有2个html,每个html各引入对应的js.
在这里插入图片描述

7.3 其他配置项

7.3.1 代码不处理压缩

打出来的代码是压缩后的,不便于阅读,可以稍加配置(minify属性)。
在这里插入图片描述

// webpack.config.js
const htmlwebpack = require('html-webpack-plugin');
module.exports = {
    // entry: "./app.js",//单入口写法,入口指定为app.js
    entry: {  // 多入口写法:入口名称+入口文件
        app1: ["./app.js"],
        app2: './app2.js'
    },
    // entry: ["./app.js", './app2.js'] // 两个文件同时作为一个入口
    output: {
        path: __dirname + '/dist', // 绝对路径,__dirname是node的全局变量,表示当前目录的绝对路径
        filename: "[name].[hash:4].bundle.js", //将name加到filename里,打包结果文件是app.bundle.js和app2.bundle.js,hash是对文件是否有改变的标志,:4表示截取前4位
    },
    mode: "production", //webpack4以后要指定mode
    // loader
    module: {
        rules: [
        ]
    },
    plugins: [
        new htmlwebpack({
            template: './index.html',// 写法1,指定html模板
            // templateContent: function () {  // 写法2,自定义模板,使用频率较低
            //     return '<div>123</div>'
            // }
            filename: "index.html",
            chunks: ["app1"],            
            minify: {
                collapseInlineTagWhitespace: false, // 是否一行展示
                removeComments: false, //是否移除注释
                removeAttributeQuotes: false, //是否移除属性之间的多余空格
            }
        }),
        new htmlwebpack({
            template: './index2.html',
            filename: "index2.html",
            chunks: ["app2"]
        })
    ]
}

配置后打包出来的index.html

// dist\index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>webpackhtml</title>
<script defer="defer" src="app1.506b.bundle.js"></script><link href="test.bundle.css" rel="stylesheet"></head>

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

</html>

7.3.2 js加载位置

  • 可以看到目前script标签是加载在head标签里的。是否可以指定js文件的加载位置(默认加载到head标签)?
    • 加入inject属性,值为body.
// webpack.config.js
const htmlwebpack = require('html-webpack-plugin');
module.exports = {
    // entry: "./app.js",//单入口写法,入口指定为app.js
    entry: {  // 多入口写法:入口名称+入口文件
        app1: ["./app.js"],
        app2: './app2.js'
    },
    // entry: ["./app.js", './app2.js'] // 两个文件同时作为一个入口
    output: {
        path: __dirname + '/dist', // 绝对路径,__dirname是node的全局变量,表示当前目录的绝对路径
        filename: "[name].[hash:4].bundle.js", //将name加到filename里,打包结果文件是app.bundle.js和app2.bundle.js,hash是对文件是否有改变的标志,:4表示截取前4位
    },
    mode: "production", //webpack4以后要指定mode
    // loader
    module: {
        rules: [
        ]
    },
    plugins: [
        new htmlwebpack({
            template: './index.html',// 写法1,指定html模板
            // templateContent: function () {  // 写法2,自定义模板,使用频率较低
            //     return '<div>123</div>'
            // }
            filename: "index.html",
            chunks: ["app1"],            
            minify: {
                collapseInlineTagWhitespace: false, // 是否一行展示
                removeComments: false, //是否移除注释
                removeAttributeQuotes: false, //是否移除属性之间的多余空格
            },
            inject: "body" // 指定js加载位置: body|true(加载到body中), head, false(不加载)
        }),
        new htmlwebpack({
            template: './index2.html',
            filename: "index2.html",
            chunks: ["app2"]
        })
    ]
}

在这里插入图片描述

7.3.3 其他配置

html的标题title标签支持可配置,也可在webpack.config.js设置。

vue项目可以实现处理,这部分就不看了。


网站公告

今日签到

点亮在社区的每一天
去签到