@vigla/vite-plugin 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +12 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +1 -0
- package/dist/api.js.map +1 -0
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +48 -0
- package/dist/compile.js.map +1 -0
- package/dist/compiler.d.ts +115 -0
- package/dist/compiler.d.ts.map +1 -0
- package/dist/compiler.js +1 -0
- package/dist/compiler.js.map +1 -0
- package/dist/config-file.d.ts +10 -0
- package/dist/config-file.d.ts.map +1 -0
- package/dist/config-file.js +63 -0
- package/dist/config-file.js.map +1 -0
- package/dist/dependencies.d.ts +3 -0
- package/dist/dependencies.d.ts.map +1 -0
- package/dist/dependencies.js +40 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/error.d.ts +7 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +49 -0
- package/dist/error.js.map +1 -0
- package/dist/front-end.d.ts +24 -0
- package/dist/front-end.d.ts.map +1 -0
- package/dist/front-end.js +120 -0
- package/dist/front-end.js.map +1 -0
- package/dist/id.d.ts +40 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +144 -0
- package/dist/id.js.map +1 -0
- package/dist/identity.d.ts +41 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +31 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +17 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +92 -0
- package/dist/log.js.map +1 -0
- package/dist/maps.d.ts +8 -0
- package/dist/maps.d.ts.map +1 -0
- package/dist/maps.js +37 -0
- package/dist/maps.js.map +1 -0
- package/dist/messages.d.ts +17 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +16 -0
- package/dist/messages.js.map +1 -0
- package/dist/options.d.ts +26 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +187 -0
- package/dist/options.js.map +1 -0
- package/dist/plugins/compile-module.d.ts +5 -0
- package/dist/plugins/compile-module.d.ts.map +1 -0
- package/dist/plugins/compile-module.js +50 -0
- package/dist/plugins/compile-module.js.map +1 -0
- package/dist/plugins/compile.d.ts +5 -0
- package/dist/plugins/compile.d.ts.map +1 -0
- package/dist/plugins/compile.js +40 -0
- package/dist/plugins/compile.js.map +1 -0
- package/dist/plugins/configure.d.ts +6 -0
- package/dist/plugins/configure.d.ts.map +1 -0
- package/dist/plugins/configure.js +54 -0
- package/dist/plugins/configure.js.map +1 -0
- package/dist/plugins/hot-update.d.ts +5 -0
- package/dist/plugins/hot-update.d.ts.map +1 -0
- package/dist/plugins/hot-update.js +137 -0
- package/dist/plugins/hot-update.js.map +1 -0
- package/dist/plugins/load.d.ts +6 -0
- package/dist/plugins/load.d.ts.map +1 -0
- package/dist/plugins/load.js +77 -0
- package/dist/plugins/load.js.map +1 -0
- package/dist/plugins/optimizer.d.ts +5 -0
- package/dist/plugins/optimizer.d.ts.map +1 -0
- package/dist/plugins/optimizer.js +174 -0
- package/dist/plugins/optimizer.js.map +1 -0
- package/dist/plugins/preprocess.d.ts +11 -0
- package/dist/plugins/preprocess.d.ts.map +1 -0
- package/dist/plugins/preprocess.js +142 -0
- package/dist/plugins/preprocess.js.map +1 -0
- package/dist/plugins/runtime-scan.d.ts +4 -0
- package/dist/plugins/runtime-scan.d.ts.map +1 -0
- package/dist/plugins/runtime-scan.js +56 -0
- package/dist/plugins/runtime-scan.js.map +1 -0
- package/dist/plugins/scan.d.ts +5 -0
- package/dist/plugins/scan.d.ts.map +1 -0
- package/dist/plugins/scan.js +198 -0
- package/dist/plugins/scan.js.map +1 -0
- package/dist/preprocess.d.ts +6 -0
- package/dist/preprocess.d.ts.map +1 -0
- package/dist/preprocess.js +164 -0
- package/dist/preprocess.js.map +1 -0
- package/dist/public.d.ts +47 -0
- package/dist/public.d.ts.map +1 -0
- package/dist/public.js +1 -0
- package/dist/public.js.map +1 -0
- package/dist/vite-config.d.ts +14 -0
- package/dist/vite-config.d.ts.map +1 -0
- package/dist/vite-config.js +167 -0
- package/dist/vite-config.js.map +1 -0
- package/dist/warnings.d.ts +6 -0
- package/dist/warnings.d.ts.map +1 -0
- package/dist/warnings.js +57 -0
- package/dist/warnings.js.map +1 -0
- package/package.json +24 -5
- package/src/api.ts +12 -0
- package/src/compile.ts +96 -0
- package/src/compiler.ts +129 -0
- package/src/config-file.ts +75 -0
- package/src/dependencies.ts +47 -0
- package/src/error.ts +64 -0
- package/src/front-end.ts +146 -0
- package/src/id.ts +225 -0
- package/src/identity.ts +74 -0
- package/src/index.ts +61 -0
- package/src/log.ts +105 -0
- package/src/maps.ts +36 -0
- package/src/messages.ts +40 -0
- package/src/options.ts +257 -0
- package/src/plugins/compile-module.ts +65 -0
- package/src/plugins/compile.ts +49 -0
- package/src/plugins/configure.ts +63 -0
- package/src/plugins/hot-update.ts +159 -0
- package/src/plugins/load.ts +89 -0
- package/src/plugins/optimizer.ts +262 -0
- package/src/plugins/preprocess.ts +163 -0
- package/src/plugins/runtime-scan.ts +75 -0
- package/src/plugins/scan.ts +206 -0
- package/src/preprocess.ts +190 -0
- package/src/public.ts +56 -0
- package/src/vite-config.ts +252 -0
- package/src/warnings.ts +66 -0
- package/README.md +0 -3
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import loadPostcss from 'postcss-load-config';
|
|
4
|
+
import type { Plugin as PostcssPlugin } from 'postcss';
|
|
5
|
+
import parseValue, { type Node as ValueNode } from 'postcss-value-parser';
|
|
6
|
+
import * as vite from 'vite';
|
|
7
|
+
import type { InlineConfig, ResolvedConfig } from 'vite';
|
|
8
|
+
import type { Preprocessor, PreprocessorGroup } from './compiler.ts';
|
|
9
|
+
import { mapToRelative, removeLangSuffix, type FileRefs } from './maps.ts';
|
|
10
|
+
import type { VitePreprocessOptions } from './public.ts';
|
|
11
|
+
|
|
12
|
+
type CssTransform = (
|
|
13
|
+
code: string,
|
|
14
|
+
filename: string
|
|
15
|
+
) => Promise<{ code: string; map?: FileRefs | null; deps?: Set<string> }>;
|
|
16
|
+
|
|
17
|
+
type Oxc = (
|
|
18
|
+
code: string,
|
|
19
|
+
filename: string,
|
|
20
|
+
options: object
|
|
21
|
+
) => Promise<{ code: string; map: FileRefs | null }>;
|
|
22
|
+
|
|
23
|
+
const { isCSSRequest, preprocessCSS, resolveConfig } = vite;
|
|
24
|
+
const transformWithOxc = (vite as unknown as { transformWithOxc: Oxc }).transformWithOxc;
|
|
25
|
+
|
|
26
|
+
const scriptLangs = ['ts'];
|
|
27
|
+
const separator = '.vite-preprocess';
|
|
28
|
+
|
|
29
|
+
interface Tagged {
|
|
30
|
+
__resolvedConfig?: ResolvedConfig | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function script(): Preprocessor {
|
|
34
|
+
return async ({ attributes, content, filename = '' }) => {
|
|
35
|
+
if (typeof attributes.lang !== 'string' || !scriptLangs.includes(attributes.lang))
|
|
36
|
+
return undefined;
|
|
37
|
+
const { code, map } = await transformWithOxc(content, filename, {
|
|
38
|
+
lang: attributes.lang,
|
|
39
|
+
target: 'esnext',
|
|
40
|
+
typescript: { onlyRemoveTypeImports: true }
|
|
41
|
+
});
|
|
42
|
+
mapToRelative(map, filename);
|
|
43
|
+
return { code, map: map ?? undefined };
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function resolved(config: ResolvedConfig | InlineConfig): config is ResolvedConfig {
|
|
48
|
+
return !!(config as ResolvedConfig).inlineConfig;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function assetUrls(style: Tagged): PostcssPlugin {
|
|
52
|
+
let resolve: ReturnType<ResolvedConfig['createResolver']> | undefined;
|
|
53
|
+
return {
|
|
54
|
+
postcssPlugin: 'vite-preprocess-urls',
|
|
55
|
+
async OnceExit(root, { result }) {
|
|
56
|
+
const from = result.opts.from;
|
|
57
|
+
if (!from || !/\.vite-preprocess\.[^./]+$/.test(from)) return;
|
|
58
|
+
if (!style.__resolvedConfig)
|
|
59
|
+
throw new Error('style preprocessing has no resolved Vite config');
|
|
60
|
+
resolve ??= style.__resolvedConfig.createResolver({
|
|
61
|
+
preferRelative: true,
|
|
62
|
+
tryIndex: false,
|
|
63
|
+
extensions: []
|
|
64
|
+
});
|
|
65
|
+
const resolveAsset = resolve;
|
|
66
|
+
const declarations: Promise<void>[] = [];
|
|
67
|
+
root.walkDecls((declaration) => {
|
|
68
|
+
if (!/(?:url|image-set)\(/i.test(declaration.value)) return;
|
|
69
|
+
const importer = declaration.source?.input.file ?? from;
|
|
70
|
+
const parsed = parseValue(declaration.value);
|
|
71
|
+
const assets: Promise<void>[] = [];
|
|
72
|
+
const rebase = async (node: ValueNode): Promise<void> => {
|
|
73
|
+
const url = node.value;
|
|
74
|
+
if (!url || /^(?:[a-z][a-z\d+.-]*:|[/#~])/i.test(url)) return;
|
|
75
|
+
const suffix = url.search(/[?#]/);
|
|
76
|
+
const pathname = suffix < 0 ? url : url.slice(0, suffix);
|
|
77
|
+
const tail = suffix < 0 ? '' : url.slice(suffix);
|
|
78
|
+
const file = await resolveAsset(decodeURI(pathname), importer);
|
|
79
|
+
if (!file) return;
|
|
80
|
+
const relative = vite.normalizePath(path.relative(path.dirname(from), file));
|
|
81
|
+
node.value = `${encodeURI(relative)}${tail}`;
|
|
82
|
+
};
|
|
83
|
+
parsed.walk((node) => {
|
|
84
|
+
if (node.type !== 'function') return;
|
|
85
|
+
if (node.value.toLowerCase() === 'url') {
|
|
86
|
+
const value = node.nodes.find((part) => part.type === 'string' || part.type === 'word');
|
|
87
|
+
if (value) assets.push(rebase(value));
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (/^(?:-webkit-)?image-set$/i.test(node.value)) {
|
|
91
|
+
for (const value of node.nodes) {
|
|
92
|
+
if (value.type === 'string') assets.push(rebase(value));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
if (assets.length > 0)
|
|
97
|
+
declarations.push(
|
|
98
|
+
Promise.all(assets).then(() => {
|
|
99
|
+
declaration.value = parsed.toString();
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
await Promise.all(declarations);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function configureStyles(
|
|
109
|
+
groups: PreprocessorGroup[],
|
|
110
|
+
config: InlineConfig
|
|
111
|
+
): Promise<void> {
|
|
112
|
+
for (const group of groups) {
|
|
113
|
+
const style = group.style as (PreprocessorGroup['style'] & Tagged) | undefined;
|
|
114
|
+
if (style && '__resolvedConfig' in style) {
|
|
115
|
+
await cssConfig(style, config);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function cssConfig(style: Tagged, config: InlineConfig): Promise<void> {
|
|
122
|
+
if (config.css?.transformer === 'lightningcss') return;
|
|
123
|
+
const root = path.resolve(config.root ?? process.cwd());
|
|
124
|
+
const inline = config.css?.postcss;
|
|
125
|
+
const postcss =
|
|
126
|
+
typeof inline === 'object'
|
|
127
|
+
? inline
|
|
128
|
+
: await loadPostcss({}, inline ?? root, {
|
|
129
|
+
stopDir: vite.searchForWorkspaceRoot(root)
|
|
130
|
+
})
|
|
131
|
+
.then(({ options, plugins }) => ({ ...options, plugins }))
|
|
132
|
+
.catch((error: unknown) => {
|
|
133
|
+
if (!(error instanceof Error) || !error.message.includes('No PostCSS Config found'))
|
|
134
|
+
throw error;
|
|
135
|
+
return { plugins: [] };
|
|
136
|
+
});
|
|
137
|
+
config.css = {
|
|
138
|
+
...config.css,
|
|
139
|
+
postcss: {
|
|
140
|
+
...postcss,
|
|
141
|
+
plugins: [...(postcss.plugins ?? []), assetUrls(style)]
|
|
142
|
+
} as ResolvedConfig['css']['postcss']
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function cssTransform(
|
|
147
|
+
style: Tagged,
|
|
148
|
+
config: ResolvedConfig | InlineConfig
|
|
149
|
+
): Promise<CssTransform> {
|
|
150
|
+
let resolvedConfig: ResolvedConfig;
|
|
151
|
+
if (style.__resolvedConfig) resolvedConfig = style.__resolvedConfig;
|
|
152
|
+
else if (resolved(config)) resolvedConfig = config;
|
|
153
|
+
else {
|
|
154
|
+
const build = !process.env.NODE_ENV || process.env.NODE_ENV === 'production';
|
|
155
|
+
const mode = build ? 'production' : 'development';
|
|
156
|
+
const standalone = { ...config };
|
|
157
|
+
await cssConfig(style, standalone);
|
|
158
|
+
resolvedConfig = await resolveConfig(standalone, build ? 'build' : 'serve', mode, mode, false);
|
|
159
|
+
}
|
|
160
|
+
style.__resolvedConfig = resolvedConfig;
|
|
161
|
+
return (code, filename) =>
|
|
162
|
+
preprocessCSS(code, filename, resolvedConfig) as ReturnType<CssTransform>;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function style(config: ResolvedConfig | InlineConfig = {}): Preprocessor {
|
|
166
|
+
let transform: Promise<CssTransform> | CssTransform | undefined;
|
|
167
|
+
const run = (async ({ attributes, content, filename = '' }) => {
|
|
168
|
+
const extension = attributes.lang ? `.${attributes.lang}` : '.css';
|
|
169
|
+
if (attributes.lang && !isCSSRequest(extension)) return undefined;
|
|
170
|
+
transform ??= cssTransform(run, config).then((ready) => (transform = ready));
|
|
171
|
+
const ready = await transform;
|
|
172
|
+
const suffix = `${separator}${extension}`;
|
|
173
|
+
const { code, map, deps } = await ready(content, `${filename}${suffix}`);
|
|
174
|
+
removeLangSuffix(map, suffix);
|
|
175
|
+
mapToRelative(map, filename);
|
|
176
|
+
const dependencies = deps ? [...deps].filter((dep) => !dep.endsWith(suffix)) : undefined;
|
|
177
|
+
return { code, map: map ?? undefined, dependencies };
|
|
178
|
+
}) as Preprocessor & Tagged;
|
|
179
|
+
run.__resolvedConfig = null;
|
|
180
|
+
return run;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function vitePreprocess(options?: VitePreprocessOptions): PreprocessorGroup {
|
|
184
|
+
const group: PreprocessorGroup = { name: 'vite-preprocess' };
|
|
185
|
+
if (options?.script === true) group.script = script();
|
|
186
|
+
if (options?.style !== false) {
|
|
187
|
+
group.style = style(typeof options?.style === 'object' ? options.style : undefined);
|
|
188
|
+
}
|
|
189
|
+
return group;
|
|
190
|
+
}
|
package/src/public.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Environment, InlineConfig, ResolvedConfig } from 'vite';
|
|
2
|
+
import type { CompileOptions, PreprocessorGroup, Warning } from './compiler.ts';
|
|
3
|
+
|
|
4
|
+
type Arrayable<T> = T | T[];
|
|
5
|
+
|
|
6
|
+
export interface DynamicCompileInput {
|
|
7
|
+
filename: string;
|
|
8
|
+
code: string;
|
|
9
|
+
compileOptions: Partial<CompileOptions>;
|
|
10
|
+
environment: Environment;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type DynamicCompileOptions = (
|
|
14
|
+
data: DynamicCompileInput
|
|
15
|
+
) => Promise<Partial<CompileOptions> | void> | Partial<CompileOptions> | void;
|
|
16
|
+
|
|
17
|
+
export interface CompileModuleOptions {
|
|
18
|
+
infixes?: string[];
|
|
19
|
+
extensions?: string[];
|
|
20
|
+
include?: Arrayable<string | RegExp>;
|
|
21
|
+
exclude?: Arrayable<string | RegExp>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ExperimentalOptions {
|
|
25
|
+
sendWarningsToBrowser?: boolean;
|
|
26
|
+
disableResolveWarnings?: boolean;
|
|
27
|
+
compileModule?: CompileModuleOptions;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface PluginOptions {
|
|
31
|
+
include?: Arrayable<string | RegExp>;
|
|
32
|
+
exclude?: Arrayable<string | RegExp>;
|
|
33
|
+
emitCss?: boolean;
|
|
34
|
+
disableDependencyReinclusion?: boolean | string[];
|
|
35
|
+
prebundleLibraries?: boolean;
|
|
36
|
+
inspector?: boolean | object;
|
|
37
|
+
dynamicCompileOptions?: DynamicCompileOptions;
|
|
38
|
+
experimental?: ExperimentalOptions;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Config {
|
|
42
|
+
extensions?: string[];
|
|
43
|
+
preprocess?: Arrayable<PreprocessorGroup>;
|
|
44
|
+
compilerOptions?: Omit<CompileOptions, 'filename' | 'format' | 'generate'>;
|
|
45
|
+
onwarn?: (warning: Warning, defaultHandler: (warning: Warning) => void) => void;
|
|
46
|
+
vitePlugin?: PluginOptions;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface Options extends Omit<Config, 'vitePlugin'>, PluginOptions {
|
|
50
|
+
configFile?: string | false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface VitePreprocessOptions {
|
|
54
|
+
script?: boolean;
|
|
55
|
+
style?: boolean | InlineConfig | ResolvedConfig;
|
|
56
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultClientConditions,
|
|
3
|
+
defaultClientMainFields,
|
|
4
|
+
defaultServerConditions,
|
|
5
|
+
defaultServerMainFields,
|
|
6
|
+
searchForWorkspaceRoot,
|
|
7
|
+
type EnvironmentOptions,
|
|
8
|
+
type UserConfig
|
|
9
|
+
} from 'vite';
|
|
10
|
+
import {
|
|
11
|
+
crawlFrameworkPkgs,
|
|
12
|
+
isDepExcluded,
|
|
13
|
+
isDepExternaled,
|
|
14
|
+
isDepIncluded,
|
|
15
|
+
isDepNoExternaled,
|
|
16
|
+
type CrawlFrameworkPkgsResult
|
|
17
|
+
} from 'vitefu';
|
|
18
|
+
import { shipsNoSources } from './dependencies.ts';
|
|
19
|
+
import type { FrontEnd } from './front-end.ts';
|
|
20
|
+
import type { Identity } from './identity.ts';
|
|
21
|
+
import type { Log } from './log.ts';
|
|
22
|
+
import type { PreResolvedOptions } from './options.ts';
|
|
23
|
+
|
|
24
|
+
interface Lists {
|
|
25
|
+
optimizeDeps: { include: string[]; exclude: string[] };
|
|
26
|
+
ssr: { noExternal: (string | RegExp)[]; external: string[] };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function deduped(frontEnd: FrontEnd): string[] {
|
|
30
|
+
return frontEnd.imports.filter((name) => name !== frontEnd.compilerImport);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function clientImports(frontEnd: FrontEnd): string[] {
|
|
34
|
+
return deduped(frontEnd).filter(
|
|
35
|
+
(name) => !name.endsWith('/server') && !name.includes('/server/')
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function escape(text: string): string {
|
|
40
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function frontEndLists(config: UserConfig, frontEnds: readonly FrontEnd[], log: Log): Lists {
|
|
44
|
+
const include: string[] = [];
|
|
45
|
+
const noExternal: (string | RegExp)[] = [];
|
|
46
|
+
for (const frontEnd of frontEnds) {
|
|
47
|
+
if (!isDepExcluded(frontEnd.name, config.optimizeDeps?.exclude ?? [])) {
|
|
48
|
+
const imports = clientImports(frontEnd);
|
|
49
|
+
log.debug(
|
|
50
|
+
`adding bare ${frontEnd.name} packages to optimizeDeps.include: ${imports.join(', ')} `,
|
|
51
|
+
undefined,
|
|
52
|
+
'config'
|
|
53
|
+
);
|
|
54
|
+
include.push(...imports);
|
|
55
|
+
} else {
|
|
56
|
+
log.debug(
|
|
57
|
+
`"${frontEnd.name}" is excluded in optimizeDeps.exclude, skipped adding it to include.`,
|
|
58
|
+
undefined,
|
|
59
|
+
'config'
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (!isDepExternaled(frontEnd.name, config.ssr?.external ?? [])) {
|
|
63
|
+
noExternal.push(frontEnd.name, new RegExp(`^${escape(frontEnd.name)}\\/`));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!isDepExternaled('esm-env', config.ssr?.external ?? [])) noExternal.push('esm-env');
|
|
67
|
+
return { optimizeDeps: { include, exclude: [] }, ssr: { noExternal, external: [] } };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hasCondition(exports: unknown, conditions: readonly string[]): boolean {
|
|
71
|
+
if (exports === null || typeof exports !== 'object') return false;
|
|
72
|
+
let found = false;
|
|
73
|
+
JSON.stringify(exports, (key, value) => {
|
|
74
|
+
if (conditions.includes(key)) found = true;
|
|
75
|
+
return value;
|
|
76
|
+
});
|
|
77
|
+
return found;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function dependencyLists(
|
|
81
|
+
options: PreResolvedOptions,
|
|
82
|
+
config: UserConfig,
|
|
83
|
+
frontEnds: readonly FrontEnd[],
|
|
84
|
+
{ names: vocabulary, messages, log }: Identity
|
|
85
|
+
): Promise<CrawlFrameworkPkgsResult> {
|
|
86
|
+
const conditions = frontEnds.map((frontEnd) => frontEnd.condition);
|
|
87
|
+
const names = new Set(frontEnds.map((frontEnd) => frontEnd.name));
|
|
88
|
+
const withoutCondition = new Set<string>();
|
|
89
|
+
const lists = await crawlFrameworkPkgs({
|
|
90
|
+
root: options.root,
|
|
91
|
+
workspaceRoot: searchForWorkspaceRoot(options.root),
|
|
92
|
+
isBuild: options.isBuild,
|
|
93
|
+
viteUserConfig: config,
|
|
94
|
+
isFrameworkPkgByJson(manifest) {
|
|
95
|
+
const condition = hasCondition(manifest.exports, conditions);
|
|
96
|
+
const field = conditions.some((name) => !!manifest[name]);
|
|
97
|
+
if (field && !condition) withoutCondition.add(`${manifest.name}@${manifest.version}`);
|
|
98
|
+
return condition || field;
|
|
99
|
+
},
|
|
100
|
+
isSemiFrameworkPkgByJson(manifest) {
|
|
101
|
+
return [...names].some(
|
|
102
|
+
(name) => !!manifest.dependencies?.[name] || !!manifest.peerDependencies?.[name]
|
|
103
|
+
);
|
|
104
|
+
},
|
|
105
|
+
isFrameworkPkgByName(name) {
|
|
106
|
+
return names.has(name) || shipsNoSources(vocabulary, name) ? false : undefined;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
if (
|
|
110
|
+
!options.isBuild &&
|
|
111
|
+
!options.experimental?.disableResolveWarnings &&
|
|
112
|
+
withoutCondition.size > 0
|
|
113
|
+
) {
|
|
114
|
+
const link = vocabulary.links.missingCondition;
|
|
115
|
+
log.info.once(
|
|
116
|
+
`${messages.missingCondition(conditions)}\n\n${[...withoutCondition].join('\n')}${link ? `\n\nPlease see ${link} for details.` : ''}`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
log.debug('extra config for dependencies generated by vitefu', lists, 'config');
|
|
120
|
+
if (options.prebundleLibraries) {
|
|
121
|
+
lists.optimizeDeps.exclude = [];
|
|
122
|
+
const excluded = config.optimizeDeps?.exclude;
|
|
123
|
+
lists.optimizeDeps.include = !excluded
|
|
124
|
+
? []
|
|
125
|
+
: lists.optimizeDeps.include.filter(
|
|
126
|
+
(dep) =>
|
|
127
|
+
dep.includes('>') &&
|
|
128
|
+
dep
|
|
129
|
+
.split('>')
|
|
130
|
+
.slice(0, -1)
|
|
131
|
+
.some((part) => isDepExcluded(part.trim(), excluded))
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
const disabled = options.disableDependencyReinclusion;
|
|
135
|
+
if (disabled === true) {
|
|
136
|
+
lists.optimizeDeps.include = lists.optimizeDeps.include.filter((dep) => !dep.includes('>'));
|
|
137
|
+
} else if (Array.isArray(disabled)) {
|
|
138
|
+
lists.optimizeDeps.include = lists.optimizeDeps.include.filter((dep) => {
|
|
139
|
+
if (!dep.includes('>')) return true;
|
|
140
|
+
const trimmed = dep.replace(/\s+/g, '');
|
|
141
|
+
return disabled.some((name) => trimmed.includes(`${name}>`));
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
log.debug('post-processed extra config for dependencies', lists, 'config');
|
|
145
|
+
return lists;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function validateViteConfig(
|
|
149
|
+
extra: UserConfig,
|
|
150
|
+
config: UserConfig,
|
|
151
|
+
options: PreResolvedOptions,
|
|
152
|
+
{ names, log }: Identity
|
|
153
|
+
): void {
|
|
154
|
+
const { prebundleLibraries, isBuild } = options;
|
|
155
|
+
if (prebundleLibraries) {
|
|
156
|
+
const enabled = (option: 'dev' | 'build' | boolean) =>
|
|
157
|
+
option !== true && option !== (isBuild ? 'build' : 'dev');
|
|
158
|
+
const warn = (name: string, value: unknown, recommendation: string) =>
|
|
159
|
+
log.warn.once(
|
|
160
|
+
`Incompatible options: \`${names.prebundle}: true\` and vite \`${name}: ${JSON.stringify(value)}\` ${isBuild ? 'during build.' : '.'} ${recommendation}`
|
|
161
|
+
);
|
|
162
|
+
const disabled = config.optimizeDeps?.disabled ?? 'build';
|
|
163
|
+
const optimizing = enabled(disabled);
|
|
164
|
+
if (!isBuild && !optimizing) {
|
|
165
|
+
warn(
|
|
166
|
+
'optimizeDeps.disabled',
|
|
167
|
+
disabled,
|
|
168
|
+
`Forcing \`optimizeDeps.disabled: "build"\`. Disable ${names.prebundle} or update your vite config to enable optimizeDeps during dev.`
|
|
169
|
+
);
|
|
170
|
+
extra.optimizeDeps ??= {};
|
|
171
|
+
extra.optimizeDeps.disabled = 'build';
|
|
172
|
+
} else if (isBuild && optimizing) {
|
|
173
|
+
warn(
|
|
174
|
+
'optimizeDeps.disabled',
|
|
175
|
+
disabled,
|
|
176
|
+
`Disable optimizeDeps or ${names.prebundle} for build if you experience errors.`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (isBuild) {
|
|
181
|
+
type Optimization = { optimization?: { inlineConst?: boolean } };
|
|
182
|
+
const build = config.build as
|
|
183
|
+
| { rolldownOptions?: Optimization; rollupOptions?: Optimization }
|
|
184
|
+
| undefined;
|
|
185
|
+
const inlineConst =
|
|
186
|
+
build?.rolldownOptions?.optimization?.inlineConst ??
|
|
187
|
+
build?.rollupOptions?.optimization?.inlineConst;
|
|
188
|
+
if (inlineConst === false) {
|
|
189
|
+
log.warn(
|
|
190
|
+
'Your rolldown config contains `optimization.inlineConst: false`. This can lead to increased bundle size and leaked server code in client build.'
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function buildExtraViteConfig(
|
|
197
|
+
options: PreResolvedOptions,
|
|
198
|
+
config: UserConfig,
|
|
199
|
+
frontEnds: readonly FrontEnd[],
|
|
200
|
+
identity: Identity
|
|
201
|
+
): Promise<UserConfig> {
|
|
202
|
+
const { log } = identity;
|
|
203
|
+
const extra: UserConfig = { resolve: { dedupe: frontEnds.flatMap(deduped) } };
|
|
204
|
+
const own = frontEndLists(config, frontEnds, log);
|
|
205
|
+
const deps = await dependencyLists(options, config, frontEnds, identity);
|
|
206
|
+
extra.optimizeDeps = {
|
|
207
|
+
include: [
|
|
208
|
+
...own.optimizeDeps.include,
|
|
209
|
+
...deps.optimizeDeps.include.filter((dep) => !isDepExcluded(dep, own.optimizeDeps.exclude))
|
|
210
|
+
],
|
|
211
|
+
exclude: [
|
|
212
|
+
...own.optimizeDeps.exclude,
|
|
213
|
+
...deps.optimizeDeps.exclude.filter((dep) => !isDepIncluded(dep, own.optimizeDeps.include))
|
|
214
|
+
]
|
|
215
|
+
};
|
|
216
|
+
extra.ssr = {
|
|
217
|
+
external: [
|
|
218
|
+
...own.ssr.external,
|
|
219
|
+
...deps.ssr.external.filter((dep) => !isDepNoExternaled(dep, own.ssr.noExternal))
|
|
220
|
+
],
|
|
221
|
+
noExternal: [
|
|
222
|
+
...own.ssr.noExternal,
|
|
223
|
+
...deps.ssr.noExternal.filter((dep) => !isDepExternaled(dep, own.ssr.external))
|
|
224
|
+
]
|
|
225
|
+
};
|
|
226
|
+
if (config.experimental?.hmrPartialAccept !== false) {
|
|
227
|
+
log.debug('enabling "experimental.hmrPartialAccept" in vite config', undefined, 'config');
|
|
228
|
+
extra.experimental = { hmrPartialAccept: true };
|
|
229
|
+
}
|
|
230
|
+
validateViteConfig(extra, config, options, identity);
|
|
231
|
+
return extra;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function client(
|
|
235
|
+
name: string,
|
|
236
|
+
config: EnvironmentOptions,
|
|
237
|
+
opts: { isSsrTargetWebworker?: boolean }
|
|
238
|
+
) {
|
|
239
|
+
return config.consumer === 'client' || name === 'client' || !!opts.isSsrTargetWebworker;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function ensureEnvironmentResolve(
|
|
243
|
+
name: string,
|
|
244
|
+
config: EnvironmentOptions,
|
|
245
|
+
opts: { isSsrTargetWebworker?: boolean }
|
|
246
|
+
): { mainFields: string[]; conditions: string[] } {
|
|
247
|
+
config.resolve ??= {};
|
|
248
|
+
const onClient = client(name, config, opts);
|
|
249
|
+
config.resolve.mainFields ??= [...(onClient ? defaultClientMainFields : defaultServerMainFields)];
|
|
250
|
+
config.resolve.conditions ??= [...(onClient ? defaultClientConditions : defaultServerConditions)];
|
|
251
|
+
return config.resolve as { mainFields: string[]; conditions: string[] };
|
|
252
|
+
}
|
package/src/warnings.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Warning } from './compiler.ts';
|
|
2
|
+
import type { ModuleRequest } from './id.ts';
|
|
3
|
+
import type { Identity } from './identity.ts';
|
|
4
|
+
import { buildExtendedLogMessage, type Log } from './log.ts';
|
|
5
|
+
import type { ResolvedOptions } from './options.ts';
|
|
6
|
+
|
|
7
|
+
function ignored(warning: Warning, isBuild: boolean, emitCss: boolean): boolean {
|
|
8
|
+
return (
|
|
9
|
+
(!emitCss && warning.code === 'css_unused_selector') ||
|
|
10
|
+
(!isBuild && warning.code === 'css_unused_selector' && warning.message.includes('"*"'))
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function warnDev(log: Log, warning: Warning): void {
|
|
15
|
+
if (warning.filename?.includes('node_modules')) {
|
|
16
|
+
if (log.debugs('node-modules-onwarn')) {
|
|
17
|
+
log.debug(buildExtendedLogMessage(warning), undefined, 'node-modules-onwarn');
|
|
18
|
+
}
|
|
19
|
+
} else if (log.info.enabled) {
|
|
20
|
+
log.info(buildExtendedLogMessage(warning));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function warnBuild(log: Log, warning: Warning): void {
|
|
25
|
+
if (warning.filename?.includes('node_modules')) {
|
|
26
|
+
if (log.debugs('node-modules-onwarn')) {
|
|
27
|
+
log.debug(buildExtendedLogMessage(warning), warning.frame, 'node-modules-onwarn');
|
|
28
|
+
}
|
|
29
|
+
} else if (log.warn.enabled) {
|
|
30
|
+
log.warn(buildExtendedLogMessage(warning), warning.frame);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function logCompilerWarnings(
|
|
35
|
+
request: ModuleRequest,
|
|
36
|
+
warnings: Warning[],
|
|
37
|
+
options: ResolvedOptions,
|
|
38
|
+
{ log, names }: Identity
|
|
39
|
+
): void {
|
|
40
|
+
const { emitCss, onwarn, isBuild } = options;
|
|
41
|
+
const viaSocket = !isBuild && options.experimental?.sendWarningsToBrowser;
|
|
42
|
+
const handled: Warning[] = [];
|
|
43
|
+
const base = (warning: Warning) => (isBuild ? warnBuild : warnDev)(log, warning);
|
|
44
|
+
const warn = viaSocket
|
|
45
|
+
? (warning: Warning) => {
|
|
46
|
+
handled.push(warning);
|
|
47
|
+
base(warning);
|
|
48
|
+
}
|
|
49
|
+
: base;
|
|
50
|
+
const kept = warnings?.filter((warning) => !ignored(warning, isBuild, emitCss)) ?? [];
|
|
51
|
+
for (const warning of kept) {
|
|
52
|
+
if (onwarn) onwarn(warning, warn);
|
|
53
|
+
else warn(warning);
|
|
54
|
+
}
|
|
55
|
+
if (!viaSocket) return;
|
|
56
|
+
log.debug(`sending ${names.warningsEvent} message for ${request.normalizedFilename}`);
|
|
57
|
+
options.server?.ws?.send(names.warningsEvent, {
|
|
58
|
+
id: request.id,
|
|
59
|
+
filename: request.filename,
|
|
60
|
+
normalizedFilename: request.normalizedFilename,
|
|
61
|
+
timestamp: request.timestamp,
|
|
62
|
+
warnings: handled,
|
|
63
|
+
allWarnings: kept,
|
|
64
|
+
rawWarnings: warnings
|
|
65
|
+
});
|
|
66
|
+
}
|
package/README.md
DELETED