Skip to content

Commit

Permalink
feat: 支持在html/js/css资源中内联占位图片
Browse files Browse the repository at this point in the history
  • Loading branch information
pengzhanbo committed Jan 10, 2023
1 parent f929fef commit f2f2c3a
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"cSpell.words": ["middlewares"]
"cSpell.words": ["libvips", "middlewares", "npmrc"]
}
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@

## 安装

> 还未正式发布到 npm
```sh
npm i -D vite-plugin-image-placeholder
```

由于插件以来 `sharp` 库生成图片资源。`sharp`在安装过程中依赖 `libvips`,在中国地区安装可能失败。
由于插件依赖 `sharp` 库生成图片资源。`sharp`在安装过程中依赖 `libvips`,在中国地区安装可能失败。

解决方式是,在 项目的根目录中的 `.npmrc` 文件中,写入以下配置:

Expand Down Expand Up @@ -70,5 +68,4 @@ const rules = [

- [x] 开发时为 `GET` 请求的生成图片
- [x] 通过模块引入的资源生成图片资源
- [ ] 在 HTML/CSS 中引入的占位图片资源替换为base64
- [ ] 在 js 中通过 字符串引入的资源替换为 base64
- [x] 在 HTML/CSS 中引入的占位图片资源替换为base64
6 changes: 6 additions & 0 deletions example/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.img {
width: 300px;
height: 169px;
background: url('/image/placeholder') no-repeat;
background-size: cover;
}
1 change: 1 addition & 0 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<title>Mock Server Example</title>
</head>
<body>
<div class="img"></div>
<img src="/image/placeholder" alt="">
<img src="/image/placeholder/200" alt="">
<img src="/image/placeholder/300/200" alt="">
Expand Down
13 changes: 12 additions & 1 deletion example/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import placeholder from 'virtual:image/placeholder'
import './index.css'

import placeholder from 'virtual:image/placeholder/text/import'

const img = new Image()
img.src = placeholder

document.body.appendChild(img)

const img1 = new Image()
img1.src = '/image/placeholder'

const img2 = new Image()
img2.src = '/image/placeholder/text/ssss2'

document.body.appendChild(img1)
document.body.appendChild(img2)
2 changes: 1 addition & 1 deletion example/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { defineConfig } from 'vite'
import imagePlaceholder from '../src/index'

export default defineConfig(() => ({
plugins: [imagePlaceholder()],
plugins: [imagePlaceholder({ inline: false })],
}))
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
"placeholder",
"image-placeholder"
],
"repository": {
"type": "git",
"url": "https://github.com/pengzhanbo/vite-plugin-image-placeholder"
},
"license": "GPL-3.0",
"author": "pengzhanbo <[email protected]> (https://github.com/pengzhanbo)",
"type": "module",
Expand Down Expand Up @@ -39,6 +43,7 @@
"dependencies": {
"debug": "^4.3.4",
"lru-cache": "^7.14.1",
"magic-string": "^0.27.0",
"path-to-regexp": "^6.2.1",
"rgb-hex": "^4.0.0",
"sharp": "^0.31.3"
Expand Down
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { imagePlaceholderPlugin } from './plugin'
import type {
ImagePlaceholderOptions,
ImagePlaceholderParams,
ImagePlaceholderQuery,
} from './types'

export { imagePlaceholderPlugin }

export type {
ImagePlaceholderOptions,
ImagePlaceholderParams,
ImagePlaceholderQuery,
}

export default imagePlaceholderPlugin
9 changes: 4 additions & 5 deletions src/pathRules.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
export function generatePathRules(prefix: string) {
return [
'',
'/:width?/:height?{.:type}?',
'/bg/:background/:width?/:height?{.:type}?',
'/text/:text/:width?/:height?{.:type}?',
'/text/:text/bg/:background/:width?/:height?{.:type}?',
'/bg/:background/text/:text/:width?/:height?{.:type}?',
'/text/:text/bg/:background/:width?/:height?{.:type}?',
'/text/:text/:width?/:height?{.:type}?',
'/bg/:background/:width?/:height?{.:type}?',
'/:width?/:height?{.:type}?',
].map((_) => `${prefix}${_}`)
}
41 changes: 27 additions & 14 deletions src/pathToImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export async function pathToImage(
})

if (!rule) return

const urlMatch = match(rule, { decode: decodeURIComponent })(pathname!) || {
params: {
width: options.width,
Expand Down Expand Up @@ -72,7 +71,13 @@ export async function pathToImage(
rgba: true,
}

const imgBuf = await createImage(imgType, createOptions, textOptions)
const imgBuf = await createImage({
type: imgType,
create: createOptions,
text: textOptions,
quality: options.quality,
compressionLevel: options.compressionLevel,
})
const result: ImageCacheItem = {
type: imgType,
buffer: imgBuf,
Expand All @@ -81,34 +86,42 @@ export async function pathToImage(
return result
}

export async function createImage(
type: ImageType = 'png',
createOptions: CreateOptions,
textOptions?: TextOptions,
) {
let image = sharp({ create: createOptions })
export async function createImage({
type = 'png',
create,
text,
quality,
compressionLevel,
}: {
type: ImageType
create: CreateOptions
text: TextOptions
quality: number
compressionLevel: number
}) {
let image = sharp({ create })

textOptions && image.composite([{ input: { text: textOptions } }])
text && image.composite([{ input: { text } }])

switch (type) {
case 'jpg':
case 'jpeg':
image = image.jpeg({ quality: 100 })
image = image.jpeg({ quality })
break
case 'webp':
image = image.webp({ quality: 100 })
image = image.webp({ quality })
break
case 'heif':
image = image.heif({ quality: 100 })
image = image.heif({ quality })
break
case 'avif':
image = image.avif({ quality: 100 })
image = image.avif({ quality })
break
case 'gif':
image = image.gif()
break
default:
image = image.png({ compressionLevel: 1 })
image = image.png({ compressionLevel })
}

const buf = await image.toBuffer()
Expand Down
Loading

0 comments on commit f2f2c3a

Please sign in to comment.