前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >webpack 打包第三方库里有图片,集成包的时候图片变成本地路径加载不上,追寻了半天终于解决了困扰很久的问题。

webpack 打包第三方库里有图片,集成包的时候图片变成本地路径加载不上,追寻了半天终于解决了困扰很久的问题。

作者头像
星宇大前端
发布2022-03-09 11:26:32
1.7K0
发布2022-03-09 11:26:32
举报
文章被收录于专栏:大宇笔记

前言

很久之前就遇到过这个问题,一直在造轮子,难免会遇到一些库需要放图片作为背景图,上次是作为内联base64解决这个问题,但是也没有追寻为什么。这次又遇到了这个问题,应该仔仔细细弄个清楚,并花时间整理记录一下。

一、环境背景

  • 打包工具: webpack5
  • 系统: MacOS
  • 发布到npm 公有镜像

这次是打包上篇文章的3d-earth 组件,threejs 需要一些纹理地图,为了简单引用就不让外部传入纹理图片,所以需要包内纹理打包图片。

webpack5 图片资源打包简介

在 webpack 5 之前,通常使用:

raw-loader 将文件导入为字符串 url-loader 将文件作为 data URI 内联到 bundle 中 file-loader 将文件发送到输出目录 资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:

  • asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
  • asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现。
  • asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
  • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过

使用 url-loader,并且配置资源体积限制实现。 当在 webpack 5 中使用旧的 assets loader(如 file-loader/url-loader/raw-loader 等)和 asset 模块时,你可能想停止当前 asset 模块的处理,并再次启动处理,这可能会导致 asset 重复,你可以通过将 asset 模块的类型设置为 ‘javascript/auto’ 来解决。

我使用的图片打包配置

代码语言:javascript
复制
{
    test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
    type: "asset"
},

现在,webpack 将按照默认条件,自动地在 resource 和 inline 之间进行选择:小于 8kb 的文件,将会视为 inline 模块类型,否则会被视为 resource 模块类型。

打包完之后的组件包:

在这里插入图片描述
在这里插入图片描述

可以看出有图片已经打包成resource 处理了,如果将打包后的js直接放到Html 中引用也是没有问题的,路径也正确。

二、问题描述

问题步骤

  1. webpack5 打包dist
  2. 将dist发布到npm
  3. 使用umi 集成包或者其他经过webpack 打包工程集成
  4. 将会出现图片加载失败,已屏蔽图片,图片是一个file://本地连接

三、问题追踪、分析

问:为什么会是本地路径呢?

带着这个问题,一起看一个打包之后的代码

先看这一段:

代码语言:javascript
复制
/***/ "./src/img/earth_glow.png":
/*!********************************!*\
  !*** ./src/img/earth_glow.png ***!
  \********************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

eval("module.exports = __webpack_require__.p + \"9e4abf8518ca87b87326.png\";\n\n//# sourceURL=webpack://3d-earth/./src/img/earth_glow.png?");

/***/ }),

不难看出最终图片输出的路径是:webpack_require.p + 图片名 问:webpack_require.p 是什么路径呢?

__webpack_require是webpack 打包的核心函数,webpack_require.p一般是从 output.publicPath 读取的。

output.publicPath

可以参考官网了解详情 :传送门

重点看下常用几种类型:

代码语言:javascript
复制
 output: {
    // One of the below
    publicPath: 'auto', // It automatically determines the public path from either `import.meta.url`, `document.currentScript`, `<script />` or `self.location`.
    publicPath: 'https://cdn.example.com/assets/', // CDN(总是 HTTPS 协议)
    publicPath: '//cdn.example.com/assets/', // CDN(协议相同)
    publicPath: '/assets/', // 相对于服务(server-relative)
    publicPath: 'assets/', // 相对于 HTML 页面
    publicPath: '../assets/', // 相对于 HTML 页面
    publicPath: '', // 相对于 HTML 页面(目录相同)
  },

如果什么不设置的时候也就auto,这时候默认路径是 import.meta.url

import.meta

import.meta是一个给JavaScript模块暴露特定上下文的元数据属性的对象。它包含了这个模块的信息,比如说这个模块的URL。

在这里插入图片描述
在这里插入图片描述

问题总述

不难看出,我没有设置output.publicPath,所以默认是auto也就是import.meta.url 所以最后图片是一个本地file路径

四、问题解决

问题分析出了原因,那么如果以后我们想在第三方包里加图片应该怎么办呢?

我最后归纳出了几种办法,如果有更好的欢迎留言:

  1. 将webapck 打包里的图片设置为asset/inline,这样打包内联成base64,就不会有路径问题了
  2. 设置图片为url连接动态加载,也就规避了这种问题
  3. 于2方案相同,更专业就是设置统一cdn连接。 publicPath: ‘//cdn.example.com/assets/’, // CDN(协议相同)
  4. 其实我觉得这个问题是不应该出现的,图片是否应该交给外部提供更好呢?所以留个属性接口由外部提供也能解决这个问题,这是属于设计层面的办法。

我一直觉得有更好的解决办法,欢迎留言区大佬赐教

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、环境背景
    • webpack5 图片资源打包简介
      • 我使用的图片打包配置
      • 二、问题描述
        • 问题步骤
        • 三、问题追踪、分析
          • output.publicPath
            • import.meta
              • 问题总述
              • 四、问题解决
              相关产品与服务
              内容分发网络 CDN
              内容分发网络(Content Delivery Network,CDN)通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档