/
index.ts
114 lines (106 loc) · 4.23 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import type { Plugin } from "vite";
import { processAsset } from "./processing/asset";
import { processHtml } from "./processing/html";
import { processCode } from "./processing/js";
export interface HtmlAdvancedOptions {
/**
* `(rel: string, href: string) => void`
*/
functionNameAddLinkTag: string;
/**
* This string in your HTML file will be replaced to `functionNameAddLinkTag` expressions.
*/
addLinkTagsPlaceholder: string;
/**
* `(attributes: Record<string, string>, inlineScriptCode?: string) => void`
*/
functionNameAddScriptTag: string;
/**
* This string in your HTML file will be replaced to `functionNameAddScriptTag` expressions.
*/
addScriptTagsPlaceholder: string;
}
export interface Options {
/**
* The expression to use as `config.base`, a.k.a. the value you assign to __webpack_public_path__ in
* Webpack.
*
* The expression should evaluate to a string ending with "/".
*/
publicPathExpression: string;
/**
* Any script tags whose src or data-src attributes match the provided filter(s) will not be rewritten.
*/
excludeScripts?: ReadonlyArray<string | RegExp> | string | RegExp;
/**
* ### `string`
*
* Pass a string to NOT to use dynamic public path in `index.html` but remove the impact of placeholder
* `config.base`. Use it if you want to handle processing of `index.html` yourself.
*
* This is NOT recommanded. See also `false` below.
*
* NOTE: For modern build, this doesn't match Webpack's behavior "load initial JS/CSS files from original
* host but imported from dynamic public path", because ES module imports generated by Vite use ALL *relative*
* URLs. For legacy build it matches that behavior.
*
* ### `boolean`
*
* Pass `true` to enable simple `index.html` substitution. All `<link>` tags will be added with
* an inline `<script>` just after ALL existing `<script>` tags in `<head>`. All `<script>` tags
* will be added with an inline `<script>` just after ALL existing `<script>` tags in `<body>`.
*
* You should initialize the value of your public path expression in a `<script>` in `<head>`.
*
* Pass `false` to disable `index.html` processing. *WARNING:* this will cause the output `index.html`
* contains the base placeholder, which lead to unusable HTML. You should handle `index.html` processing
* yourself.
*
* ### `HtmlAdvancedOptions`
*
* You will need to implement two functions `addLinkTag` and `addScriptTag`. And two placeholders
* in contexts with access to those two functions. All `<link>` and `<script>` tags will be
* transformed to calls to those two functions.
*
* You should initialize the value of your public path expression before your placeholders.
*/
html: string | boolean | HtmlAdvancedOptions;
}
export type ViteConfig = Parameters<Plugin["configResolved"]>[0];
export function publicPath(options: Options): Plugin {
let viteConfig: ViteConfig;
return {
name: "vite-plugin-public-path",
enforce: "post",
apply: "build",
configResolved(resolvedConfig) {
viteConfig = resolvedConfig;
/* istanbul ignore next */
if (!viteConfig.base || viteConfig.base === "/") {
throw new Error(
"Please use a unique placeholder (e.g. /__vite_base__/) for `config.base` on building (but NOT on previewing)\n" +
"Recommended changes:\n" +
` - base: ${JSON.stringify(viteConfig.base)},\n` +
` + base: process.env.NODE_ENV === "production" ? "/__vite_base__/" : "/",\n` +
" (in your Vite config)"
);
}
},
async generateBundle(_options, bundle) {
await Promise.all(
Object.entries(bundle).map(async ([, chunk]) => {
if (chunk.type === "chunk") {
chunk.code = await processCode(viteConfig, options, chunk.fileName, chunk.code);
} else if (chunk.type === "asset" && typeof chunk.source === "string") {
if (chunk.fileName.endsWith(".html")) {
chunk.source = processHtml(viteConfig, options, chunk.fileName, chunk.source);
} else {
chunk.source = processAsset(viteConfig, options, chunk.fileName, chunk.source);
}
}
})
);
}
};
}
export default publicPath;