feat(plugin-replace-assets): improve replace assets (#628)
This commit is contained in:
parent
cd2b7fd26d
commit
309be687b4
@ -18,7 +18,12 @@ badge: 新
|
||||
在这个过程中,通常需要先将资源上传到 CDN 服务,然后再获取 CDN 服务的资源链接,最后才在站点内容中使用。
|
||||
|
||||
这看起来并没有什么问题,然而在实际使用过程中,可能需要频繁的进行
|
||||
__上传资源 -> 获取资源链接 -> 在内容中使用全量资源链接__ 的操作,内容创作被频繁的打断。
|
||||
|
||||
```txt
|
||||
上传资源 -> 获取资源链接 -> 在内容中使用全量资源链接
|
||||
```
|
||||
|
||||
在此过程中,内容创作被频繁的打断。
|
||||
|
||||
此功能旨在解决这个问题。在内容创作过程中,只需要直接使用本地资源地址,由主题内部在合适的阶段,完成资源地址的替换。
|
||||
:::
|
||||
@ -93,7 +98,7 @@ interface ReplacementRule {
|
||||
|
||||
interface ReplaceAssetsOptions {
|
||||
/**
|
||||
* 自定义替换规则
|
||||
* 自定义资源替换规则
|
||||
*/
|
||||
rules?: ReplacementRule | ReplacementRule[]
|
||||
/**
|
||||
|
||||
@ -31,12 +31,12 @@ describe('plugin-replace-assets > normalizeRules', () => {
|
||||
|
||||
it('should work with single rule', () => {
|
||||
const rules = normalizeRules({
|
||||
find: '^/images/.*\.(jpe?g|png|gif|svg)$',
|
||||
find: '^/images/.*\\.(jpe?g|png|gif|svg)$',
|
||||
replacement: 'https://example.com/images/',
|
||||
})
|
||||
|
||||
expect(rules).toEqual([{
|
||||
find: '^/images/.*\.(jpe?g|png|gif|svg)$',
|
||||
find: '^/images/.*\\.(jpe?g|png|gif|svg)$',
|
||||
replacement: 'https://example.com/images/',
|
||||
}])
|
||||
})
|
||||
@ -44,22 +44,22 @@ describe('plugin-replace-assets > normalizeRules', () => {
|
||||
it('should work with multiple rules', () => {
|
||||
const rules = normalizeRules([
|
||||
{
|
||||
find: '^/images/.*\.(jpe?g|png|gif|svg)$',
|
||||
find: '^/images/.*\\.(jpe?g|png|gif|svg)$',
|
||||
replacement: 'https://example.com/images/',
|
||||
},
|
||||
{
|
||||
find: '^/medias/.*\.(mp4|ogg|ogv|webm)$',
|
||||
find: '^/medias/.*\\.(mp4|ogg|ogv|webm)$',
|
||||
replacement: 'https://example.com/medias/',
|
||||
},
|
||||
])
|
||||
|
||||
expect(rules).toEqual([
|
||||
{
|
||||
find: '^/images/.*\.(jpe?g|png|gif|svg)$',
|
||||
find: '^/images/.*\\.(jpe?g|png|gif|svg)$',
|
||||
replacement: 'https://example.com/images/',
|
||||
},
|
||||
{
|
||||
find: '^/medias/.*\.(mp4|ogg|ogv|webm)$',
|
||||
find: '^/medias/.*\\.(mp4|ogg|ogv|webm)$',
|
||||
replacement: 'https://example.com/medias/',
|
||||
},
|
||||
])
|
||||
@ -92,13 +92,13 @@ describe('plugin-replace-assets > normalizeRules', () => {
|
||||
it('should work with custom single rule', () => {
|
||||
const rules = normalizeRules({
|
||||
rules: {
|
||||
find: '^/images/.*\.(jpe?g|png|gif|svg)$',
|
||||
find: '^/images/.*\\.(jpe?g|png|gif|svg)$',
|
||||
replacement: 'https://example.com/images/',
|
||||
},
|
||||
})
|
||||
|
||||
expect(rules).toEqual([{
|
||||
find: '^/images/.*\.(jpe?g|png|gif|svg)$',
|
||||
find: '^/images/.*\\.(jpe?g|png|gif|svg)$',
|
||||
replacement: 'https://example.com/images/',
|
||||
}])
|
||||
})
|
||||
@ -107,11 +107,11 @@ describe('plugin-replace-assets > normalizeRules', () => {
|
||||
const rules = normalizeRules({
|
||||
rules: [
|
||||
{
|
||||
find: '^/images/.*\.(jpe?g|png|gif|svg)$',
|
||||
find: '^/images/.*\\.(jpe?g|png|gif|svg)$',
|
||||
replacement: 'https://example.com/images/',
|
||||
},
|
||||
{
|
||||
find: '^/medias/.*\.(mp4|ogg|ogv|webm)$',
|
||||
find: '^/medias/.*\\.(mp4|ogg|ogv|webm)$',
|
||||
replacement: 'https://example.com/medias/',
|
||||
},
|
||||
],
|
||||
@ -119,11 +119,11 @@ describe('plugin-replace-assets > normalizeRules', () => {
|
||||
|
||||
expect(rules).toEqual([
|
||||
{
|
||||
find: '^/images/.*\.(jpe?g|png|gif|svg)$',
|
||||
find: '^/images/.*\\.(jpe?g|png|gif|svg)$',
|
||||
replacement: 'https://example.com/images/',
|
||||
},
|
||||
{
|
||||
find: '^/medias/.*\.(mp4|ogg|ogv|webm)$',
|
||||
find: '^/medias/.*\\.(mp4|ogg|ogv|webm)$',
|
||||
replacement: 'https://example.com/medias/',
|
||||
},
|
||||
])
|
||||
|
||||
@ -7,7 +7,7 @@ describe('plugin-replace-assets > isMatchUrl', () => {
|
||||
it.each([
|
||||
{
|
||||
name: 'string like regexp with ^ and $',
|
||||
find: '^/images/.*\.(jpe?g|png|gif|svg)(\\?.*)?$',
|
||||
find: '^/images/.*\\.(jpe?g|png|gif|svg)(\\?.*)?$',
|
||||
expects: [
|
||||
['/images/foo.jpg', true],
|
||||
['/images/foo.png', true],
|
||||
@ -31,7 +31,7 @@ describe('plugin-replace-assets > isMatchUrl', () => {
|
||||
},
|
||||
{
|
||||
name: 'string like regexp end with $',
|
||||
find: '\.(jpe?g|png|gif|svg)$',
|
||||
find: '\\.(jpe?g|png|gif|svg)$',
|
||||
expects: [
|
||||
['/images/foo.jpg', true],
|
||||
['/images/foo.png', true],
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createAssetPattern, isHTMLRequest, isNonJsRequest, normalizeUrl } from '../src/unplugin/utils.js'
|
||||
import { createAssetPattern, normalizeUrl } from '../src/unplugin/utils.js'
|
||||
|
||||
describe('plugin-replace-assets > utils', () => {
|
||||
it('createAssetPattern', () => {
|
||||
@ -15,24 +15,6 @@ describe('plugin-replace-assets > utils', () => {
|
||||
expect(createAssetPattern('/[^/]').test(`"images/foo.jpg"`)).toBe(false)
|
||||
})
|
||||
|
||||
it('isHTMLRequest', () => {
|
||||
expect(isHTMLRequest('.html')).toBe(true)
|
||||
expect(isHTMLRequest('.htm')).toBe(true)
|
||||
expect(isHTMLRequest('.svg')).toBe(false)
|
||||
expect(isHTMLRequest('.png')).toBe(false)
|
||||
expect(isHTMLRequest('')).toBe(false)
|
||||
})
|
||||
|
||||
it('isNonJsRequest', () => {
|
||||
// everything request is js, but json is not
|
||||
expect(isNonJsRequest('.json')).toBe(true)
|
||||
expect(isNonJsRequest('.html')).toBe(false)
|
||||
expect(isNonJsRequest('.htm')).toBe(false)
|
||||
expect(isNonJsRequest('.svg')).toBe(false)
|
||||
expect(isNonJsRequest('.png')).toBe(false)
|
||||
expect(isNonJsRequest('')).toBe(false)
|
||||
})
|
||||
|
||||
it('normalizeUrl', () => {
|
||||
expect(normalizeUrl('')).toBe('')
|
||||
expect(normalizeUrl('/images/foo.jpg')).toBe('/images/foo.jpg')
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { Plugin } from 'vuepress/core'
|
||||
import type { ReplaceAssetsPluginOptions } from './options.js'
|
||||
import { addViteConfig, chainWebpack, getBundlerName } from '@vuepress/helper'
|
||||
import { addViteConfig, configWebpack, getBundlerName } from '@vuepress/helper'
|
||||
import { PLUGIN_NAME } from './constants.js'
|
||||
import { normalizeRules } from './normalizeRules.js'
|
||||
import { createVitePlugin, createWebpackPlugin } from './unplugin/index.js'
|
||||
@ -22,18 +22,17 @@ export function replaceAssetsPlugin(
|
||||
const bundle = getBundlerName(app)
|
||||
|
||||
if (bundle === 'vite') {
|
||||
const viteReplaceAssets = createVitePlugin()
|
||||
const replaceAssets = createVitePlugin()
|
||||
addViteConfig(bundlerOptions, app, {
|
||||
plugins: [viteReplaceAssets(rules)],
|
||||
plugins: [replaceAssets(rules)],
|
||||
})
|
||||
}
|
||||
|
||||
if (bundle === 'webpack') {
|
||||
chainWebpack(bundlerOptions, app, (config) => {
|
||||
const webpackReplaceAssets = createWebpackPlugin()
|
||||
config
|
||||
.plugin(PLUGIN_NAME)
|
||||
.use(webpackReplaceAssets, [rules])
|
||||
const replaceAssets = createWebpackPlugin()
|
||||
configWebpack(bundlerOptions, app, (config) => {
|
||||
config.plugins ??= []
|
||||
config.plugins.push(replaceAssets(rules))
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,31 +1,18 @@
|
||||
import type { UnpluginFactory, UnpluginOptions } from 'unplugin'
|
||||
import type { UnpluginFactory } from 'unplugin'
|
||||
import type { ReplacementRule } from '../options.js'
|
||||
import { transformAssets } from './transform.js'
|
||||
import { createAssetPattern, isHTMLRequest, isNonJsRequest } from './utils.js'
|
||||
import { createAssetPattern } from './utils.js'
|
||||
|
||||
export const unpluginFactory: UnpluginFactory<ReplacementRule[]> = (rules) => {
|
||||
const plugins: UnpluginOptions[] = []
|
||||
|
||||
if (rules.length) {
|
||||
plugins.push({
|
||||
name: 'vuepress:replace-assets',
|
||||
enforce: 'pre',
|
||||
transformInclude(id: string) {
|
||||
if (isHTMLRequest(id) || isNonJsRequest(id))
|
||||
return false
|
||||
return true
|
||||
const pattern = createAssetPattern('/[^/]')
|
||||
return {
|
||||
name: 'vuepress:replace-assets',
|
||||
enforce: 'pre',
|
||||
transform: {
|
||||
filter: { id: { exclude: [/\.json(?:$|\?)/, /\.html?$/] } },
|
||||
handler(code) {
|
||||
return transformAssets(code, pattern, rules)
|
||||
},
|
||||
transform(code) {
|
||||
return {
|
||||
code: transformAssets(
|
||||
code,
|
||||
createAssetPattern('/[^/]'),
|
||||
rules,
|
||||
),
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
return plugins
|
||||
}
|
||||
|
||||
@ -3,13 +3,12 @@ import type { ReplacementRule } from '../options.js'
|
||||
import {
|
||||
createVitePlugin as _createVitePlugin,
|
||||
createWebpackPlugin as _createWebpackPlugin,
|
||||
|
||||
} from 'unplugin'
|
||||
import { unpluginFactory } from './factory.js'
|
||||
|
||||
export const createVitePlugin: () => (
|
||||
options: ReplacementRule[]
|
||||
) => VitePlugin<any> | VitePlugin<any>[] = () => _createVitePlugin(unpluginFactory)
|
||||
) => VitePlugin | VitePlugin[] = () => _createVitePlugin(unpluginFactory)
|
||||
|
||||
export const createWebpackPlugin: () => (
|
||||
options: ReplacementRule[]
|
||||
|
||||
@ -15,16 +15,6 @@ export function createAssetPattern(prefix: string): RegExp {
|
||||
)
|
||||
}
|
||||
|
||||
const htmlLangRE = /\.(?:html|htm)$/
|
||||
|
||||
export const isHTMLRequest = (request: string): boolean => htmlLangRE.test(request)
|
||||
|
||||
const nonJsRe = /\.json(?:$|\?)/
|
||||
|
||||
export function isNonJsRequest(request: string): boolean {
|
||||
return nonJsRe.test(request)
|
||||
}
|
||||
|
||||
export function normalizeUrl(url: string, base?: string): string {
|
||||
if (!url)
|
||||
return ''
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user