Webpack 项目中 html-webpack-plugin 和 public 目录的关系

简介: 这几天一直在研究 Webpack 这些打包工具链,在研究项目启动的过程中,初步认识到平时开发时是通过 Webpack-dev-server 调用 Webpack 的打包能力结合静态资源服务器能力开发的

这几天一直在研究 Webpack 这些打包工具链,在研究项目启动的过程中,初步认识到平时开发时是通过 Webpack-dev-server 调用 Webpack 的打包能力结合静态资源服务器能力开发的

大概是下面这个图片

IMG

但是由于 webpack-dev-server 为了更快,它的打包文件都是放在缓存里的,对于我来说其实可以说是黑盒操作

首先来到我的第一个疑问

public 目录是什么?

通常基于 Webpack 的项目都会有一个 public 文件夹

比如 Vue CLI@4.5.15 创建的项目

├── node_modules
├── public
|  ├── favicon.ico
|  └── index.html
├── src
├── babel.config.js
├── package.json
├── package-lock.json
└── README.md

比如 creat react app@5.0.1

├── node_modules
├── public
|  ├── favicon.ico
|  ├── index.html
|  ├── logo192.png
|  ├── logo512.png
|  ├── manifest.json
|  └── robots.txt
├── src
├── .gitignore
├── babel.config.js
├── package.json
├── package-lock.json
└── README.md

共同点是都有 public/index.htmlpublic/favicon.ico,如果你尝试修改 index.html 还可以在浏览器中看到相应的修改

IMG

首先解密 public 目录是干什么的?

静态资源目录

public 其实是作为 Webpack 的静态资源目录,通过 http 请求的方式访问 public 目录下的文件内容,默认 http://localhost:port/ 会返回 publicindex.html

那么可不可以返回其它的文件呢?

当然可以,但是需要改动的地方会比较长,webpack-dev-server 提供的静态资源是依靠一下库的赋能

webpack-dev-server <- express <- serve-static

回到正题Webpack 作为前端工具链重要的一环,有一个很重要的作用就是热更新,并将热更新修改内容反映在我们的浏览器中,这也就是我们需要 public/index.html,为什么需要静态资源服务器

那么来到我的第二个疑问

既然 public/index.html 是热更新的入口,那么为什么没有看到脚手架创建的 publc/index.html 中存在和打包文件相关的部分呢?

我之前写过一篇文章基于 Webpack 从 0 到 1 启动一个 Vue 项目 - 掘金

里面纯手工运行了一个 Vue 项目(以单文件组件(SFC/.vue)的方式)

但里面的 index.html 需要依赖打包文件

<!-- index.html -->
<body>
  <div id="app"></div>
</body>
<script type="text/javascript" src="bundle.js" charset="utf-8"></script>
// webpack.config.js
// ...
module.exports = {
  mode: "development",
  devServer: {
    static: {
      directory: path.join(__dirname, "public"),
    },
    port: 8080,
  },
  // ...
  entry: path.join(__dirname, "./main.js"),
  output: {
    publicPath: "",
    filename: "bundle.js",
  },
  // ...
};

但脚手架的默认 index.html 是没有任何的 js 引入的,以 Vue CLI 为例

<!-- index.html -->
<!DOCTYPE html>
<html lang="">
  <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">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

但你先别急,脚手架项目运行之后的 index.html 可不是上面这样的,实际如下

<!DOCTYPE html>
<html lang="">
  <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">
    <link rel="icon" href="/favicon.ico">
    <title>vue-cli-create-demo</title>
  <link href="/js/app.js" rel="preload" as="script"><link href="/js/chunk-vendors.js" rel="preload" as="script"></head>
  <body>
    <noscript>
      <strong>We're sorry but vue-cli-create-demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  <script type="text/javascript" src="/js/chunk-vendors.js"></script><script type="text/javascript" src="/js/app.js"></script></body>
</html>

对比上下两个 index.html 的内容,多出了 .js 的引入以及 <%= htmlWebpackPlugin.options.title %> 被覆盖

所以脚手架它们到底是怎么做到呢?

IMG

html-webpack-plugin

回到上面的两个 index.html 里面有个 htmlWebpackPlugin 很关键,其实答案就在它身上,文档上关于 html-webpack-plugin 的介绍是这样的

HtmlWebpackPlugin 简化了 HTML 文件的创建,以便为你的 webpack 包提供服务。这对于那些文件名中包含哈希值,并且哈希值会随着每次编译而改变的 webpack 包特别有用。你可以让该插件为你生成一个 HTML 文件,使用  lodash 模板提供模板,或者使用你自己的  loader

那么它和 public/index.html 有什么联系呢?我从它的配置上得到了答案

IMG

其实这个 html-webpack-plugin 干的活就是会在 webpack 打包时生成 index.html 并且放置在 webpack-dev-server 设置的静态资源服务文件夹,因此会替换掉默认的 index.html
通常用户设置的 index.html 会作为 webpack-dev-server 调用 Webpack 打包能力时通过 html-webpack-plugin 的模版,基于此生成一个 index.html,因此像 Vue CLI 此类脚手架会在配置中设置插入打包文件的脚本引入,因此无需用户手动配置

大致流程如下图

IMG

要实现基本脚手架的这个能力可以参照下面的实现

// webpack.config.js
// ...
module.exports = {
  // ...
  plugins: [
    // ...
    new HtmlWebpackPlugin({
      // 设置模板
      template: "public/index.html",
      // 设置 html-webpack-plugin 以 defer 模式自动引入打包文件
      scriptLoading: "defer",
    }),
  ],
};

总结

为什么需要 html-webpack-plugin?比如生产环境的打包 js 文件其实是动态文件名,像这种情况不能够写死,因此就需要 html-webpack-plugin 去帮忙配置

参考资料

  1. HtmlWebpackPlugin - Wepback 文档
  2. html-webpack-plugin - github
相关文章
|
28天前
|
前端开发 测试技术 定位技术
如何利用HTML和CSS构建企业级网站的全过程。从项目概述到页面结构设计,再到HTML结构搭建与CSS样式设计,最后实现具体页面并进行优化提升,全面覆盖了网站开发的关键步骤
本文深入介绍了如何利用HTML和CSS构建企业级网站的全过程。从项目概述到页面结构设计,再到HTML结构搭建与CSS样式设计,最后实现具体页面并进行优化提升,全面覆盖了网站开发的关键步骤。通过实例展示了主页、关于我们、产品展示、新闻动态及联系我们等页面的设计与实现,强调了合理布局、美观设计及用户体验的重要性。旨在为企业打造一个既专业又具吸引力的线上平台。
56 7
|
1月前
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
57 2
|
1月前
|
前端开发 JavaScript
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
|
1月前
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
39 0
|
3月前
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
54 6
|
3月前
|
JavaScript 前端开发 UED
让 HTML 向 Vue.js 华丽转身:如何把 `wangEditor` 仿腾讯文档项目整合进 Vue.js
让 HTML 向 Vue.js 华丽转身:如何把 `wangEditor` 仿腾讯文档项目整合进 Vue.js
|
4月前
webpack——通过webpack-bundle-analyzer分析项目包占比情况
webpack——通过webpack-bundle-analyzer分析项目包占比情况
43 2
webpack——通过webpack-bundle-analyzer分析项目包占比情况
|
4月前
|
缓存 JSON JavaScript
简单介绍下从零搭建 Webpack 项目
本文详细介绍了Webpack中Loader的概念及其重要性。Webpack仅支持处理JS和JSON文件,而Loader能够帮助处理其他类型的文件,如CSS、图片等,并将其转换为有效的模块。文章首先解释了Loader的基本原理,接着介绍了几种常见Loader的配置和使用方法
27 1
|
4月前
|
前端开发 JavaScript API
|
4月前
|
JavaScript 前端开发 API
解锁前端开发新境界:Vue.js携手Webpack,打造高效构建流程,你的项目值得拥有!
【8月更文挑战第30天】随着前端技术的发展,模块化与组件化趋势愈发显著。Vue.js 以其简洁的 API 和灵活的组件系统,深受开发者喜爱;Webpack 则凭借强大的模块打包能力成为前端工程化的基石。两者结合,不仅简化了组件编写与引用,还通过模块热替换、代码分割等功能大幅提升开发效率。本文将通过具体示例,展示如何利用 Vue.js 和 Webpack 构建高效、有序的前端开发环境。从安装配置到实际应用,逐步解析这一组合的优势所在。
52 0