Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions src/core/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {replace, replaceImport, replaceInStringLiteral, replaceInTemplateElement
import {StringAsBytes, collectMatchingStrings, parseCode} from "./ast";

export async function transformChunk(codeStr: string, options: TransformOptions): Promise<string> {
const { base, publicPath } = options
const { base, publicPath, removeStartingSlash } = options
const [spanOffset, ast] = await parseCode(codeStr);

const strings = collectMatchingStrings(base, ast);
Expand All @@ -23,9 +23,9 @@ export async function transformChunk(codeStr: string, options: TransformOptions)

let transformed: string;
if (str.type === 'TemplateElement') {
transformed = replaceInTemplateElement(str, base, publicPath);
transformed = replaceInTemplateElement(str, base, publicPath, removeStartingSlash);
} else if (str.type === 'StringLiteral') {
transformed = replaceInStringLiteral(str, base, publicPath);
transformed = replaceInStringLiteral(str, base, publicPath, removeStartingSlash);
}

lastIdx = str.span.end - spanOffset;
Expand All @@ -44,25 +44,33 @@ export function transformAsset(code: string, options: TransformOptions) {
}

export function transformLegacyHtml(code: string, options: TransformOptions) {
const { base, publicPath } = options
const { base, publicPath, removeStartingSlash } = options
let content = replaceSrc(publicPath, code)
content = replace(base, '/', content)
content = replaceImport(publicPath, content)
const document = parse(content, { comment: true })
const legacyPolyfill = document.getElementById('vite-legacy-polyfill')
let legacyPolyfillSrc = legacyPolyfill?.getAttribute('src')

const legacyEntry = document.getElementById('vite-legacy-entry')
let legacyEntrySrc = legacyEntry?.getAttribute('data-src')
if (removeStartingSlash) {
legacyPolyfillSrc = legacyPolyfillSrc?.replace(/^\//, '')
legacyEntrySrc = legacyEntrySrc?.replace(/^\//, '')
}

if (legacyPolyfill) {
legacyPolyfill.setAttribute('data-src', legacyPolyfill.getAttribute('src'))
legacyPolyfill.setAttribute('data-src', legacyPolyfillSrc)
legacyPolyfill.removeAttribute('src')
legacyPolyfill.innerHTML = `!(function() {
var e = document.createElement('script')
e.src = ${publicPath} + document.getElementById('vite-legacy-polyfill').getAttribute('data-src');
e.src = ${publicPath} + "${legacyPolyfillSrc}";
e.onload = function() {
System.import(${publicPath}+document.getElementById('vite-legacy-entry').getAttribute('data-src'))
System.import(${publicPath} + "${legacyEntrySrc}")
};
document.body.appendChild(e)
})();`
}
const legacyEntry = document.getElementById('vite-legacy-entry')
if (legacyEntry) {
legacyEntry.innerHTML = ''
}
Expand All @@ -74,6 +82,7 @@ export function transformHtml(html: string, options: TransformOptions,transformI
const { base, publicPath } = options
const document = parse(html, { comment: true })
const baseMarker = `${base}`
const replaceMarker = options.removeStartingSlash ? '' : '/'
const assetsTags = document.querySelectorAll(`head>link[href^="${baseMarker}"],head>script[src^="${baseMarker}"]`)
const preloads = assetsTags.map(o => {
const result = {
Expand All @@ -82,7 +91,7 @@ export function transformHtml(html: string, options: TransformOptions,transformI
attrs: Object.assign(
{},
o.attrs,
o.attrs.src ? { src: o.attrs.src.replace(baseMarker, '/') } : { href: o.attrs.href.replace(baseMarker, '/') }
o.attrs.src ? { src: o.attrs.src.replace(baseMarker, replaceMarker) } : { href: o.attrs.href.replace(baseMarker, replaceMarker) }
)
}
o.parentNode.removeChild(o)
Expand Down
29 changes: 19 additions & 10 deletions src/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,39 @@ export function replaceImport(placeholder: string, code: string) {
return code.replace(/(System.import\()/g, `$1${placeholder}+`)
}

export function replaceInStringLiteral(literal: StringLiteral, base: string, placeholder: string): string {
export function replaceInStringLiteral(literal: StringLiteral, base: string, placeholder: string, removeStartingSlash: boolean): string {
const quoteMark = literal.raw.charAt(0);
const regex = new RegExp(base, 'g');
// Keep track of whether we need to add quotation marks at the beginning of the
// final output
let withStartQuote = true;

const transformedStr = literal.value.replace(regex, (match, index) => {
const resourceStartingSlash = removeStartingSlash ? '' : '/';

/**
* original StringLiteral may have escaped quote marks, so we need to use raw instead of value
* otherwise, will fail on style strings such as
* "@charset \"UTF-8\";cursor: url(/__vite_dynamic_public_path__/assets/cursor.svg);"
*
* since the value is
* @charset "UTF-8";cursor: url(/__vite_dynamic_public_path__/assets/cursor.svg);
*
* and does not reflect the escaped quote marks
*/
const transformedStr = literal.raw.replace(regex, (match, index) => {
let prefix = `${quoteMark}+`;

if (index === 0) {
prefix = '';
withStartQuote = false;
}

return `${prefix}${placeholder}+${quoteMark}/`;
return `${prefix}${placeholder}+${quoteMark}${resourceStartingSlash}`;
});

const prefix = withStartQuote ? quoteMark : '';

return `${prefix}${transformedStr}${quoteMark}`;
return `${transformedStr}`;
}

export function replaceInTemplateElement(element: TemplateElement, base: string, placeholder: string): string {
export function replaceInTemplateElement(element: TemplateElement, base: string, placeholder: string, removeStartingSlash: boolean): string {
const resourceStartingSlash = removeStartingSlash ? '' : '/';
const regex = new RegExp(base, 'g');
return element.raw.replace(regex, () => '/${' + placeholder + '}/');
return element.raw.replace(regex, () => '/${' + placeholder + '}' + resourceStartingSlash);
}
9 changes: 5 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ export function dynamicBase(options?: Options): Plugin {
const defaultOptions: Options = {
publicPath: 'window.__dynamic_base__',
transformIndexHtml: false, // maybe default true
transformIndexHtmlConfig: {}
transformIndexHtmlConfig: {},
removeStartingSlash: false
}

const { publicPath, transformIndexHtml, transformIndexHtmlConfig } = { ...defaultOptions, ...(options || {}) }
const { publicPath, transformIndexHtml, transformIndexHtmlConfig, removeStartingSlash } = { ...defaultOptions, ...(options || {}) }

// const preloadHelperId = 'vite/preload-helper'
let assetsDir = 'assets'
let base = '/'
let legacy = false
let baseOptions: TransformOptions = { assetsDir, base, legacy, publicPath: ` ${publicPath}`, transformIndexHtml }

let baseOptions: TransformOptions = { assetsDir, base, legacy, publicPath: ` ${publicPath}`, transformIndexHtml, removeStartingSlash }
return {
name: 'vite-plugin-dynamic-base',
enforce: 'post',
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface Options {
publicPath?: string,
removeStartingSlash?: boolean,
transformIndexHtml?: boolean
transformIndexHtmlConfig?: TransformIndexHtmlConfig
}
Expand Down