-
Notifications
You must be signed in to change notification settings - Fork 116
Expand file tree
/
Copy pathvitePluginDetectInput.js
More file actions
121 lines (104 loc) · 3.38 KB
/
vitePluginDetectInput.js
File metadata and controls
121 lines (104 loc) · 3.38 KB
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
115
116
117
118
119
120
121
import { defineConfig } from "vite";
import { readFileSync } from "node:fs";
import { globSync } from "tinyglobby";
/**
* @import {GlobOptions} from "tinyglobby"
* @import {UserConfig} from "vite"
*
* @callback RegexMatchCallback
* @param {RegExpMatchArray} match
* @returns {string}
*
* @typedef {Object} PluginConfig
* @property {RegExp} regex a RegExp used to match file contents matching file
* paths to be injected in the Vite configuration
* @property {RegexMatchCallback} [matchCallback] callback that transforms a
* RegExp match into a file path;
* defaults to returning the value at the last index in the RegExpMatchArray
* @property {string | string[]} [glob] patterns that match files to be read
* by the plugin;
* defaults to matching all files in the current directory and its children
* @property {Omit<GlobOptions, "patterns">} [globOptions] configuration object
* for "tinyglobby";
* defaults to ignoring files in "node_modules" and Python virtual env
*/
/**
* Reads all files that match `pluginConfig.glob` looking for strings that
* match `pluginConfig.regex`; all RegExp matches are transformed into
* strings representing file paths by `pluginConfig.matchCallback`.
*
* @param {PluginConfig} pluginConfig
* @returns {string[]}
*/
const searchMatches = (pluginConfig) => {
const { regex, matchCallback, glob, globOptions } = pluginConfig;
const globMatches = globSync(glob, globOptions);
const regexMatches = globMatches
.map((f) =>
Array.from(readFileSync(f).toString().matchAll(regex)).map(matchCallback),
)
.flat();
// remove possible duplicate imports, sort just for clarity
const result = Array.from(new Set(regexMatches)).sort();
return result;
};
/**
* Print the list of paths formatted in a more appealing way
* @param {string[]} input List of file paths
*/
const prettyPrintInput = (input) => {
console.log(
"🔍 Detected entry points:\n" +
input
.map((file, i) => (i === input.length - 1 ? " └─ " : " ├─ ") + file)
.join("\n"),
);
};
/**
* Default values for the plugin config; `regex` member is deliberately omitted
* and must be provided by the user
* @type {PluginConfig}
*/
const DEFAULT_PLUGIN_CONFIG = {
matchCallback: (match) => match.at(-1),
glob: "**/*",
globOptions: {
ignore: ["**/node_modules/*", "**/.venv/*", "**/venv/*"],
},
};
/**
* Plugin that automatically detects and injects entry points into the Vite
* config.
*
* @param {PluginConfig} pluginConfig
* @returns {UserConfig}
*/
const vitePluginDetectInput = (pluginConfig) => ({
name: "vite-plugin-detect-input",
config(config, env) {
let input = [];
// In dev mode we don't need to define entry points
if (env.mode === "development") return config;
// extend `pluginConfig` with the default values
pluginConfig = {
...DEFAULT_PLUGIN_CONFIG,
...pluginConfig,
};
if (!pluginConfig.regex) {
throw new Error("⚠️ Must provide a `regex` value in the plugin config");
}
input = searchMatches(pluginConfig);
if (input.length === 0) {
throw new Error("⚠️ Can't find any entry points for production build");
}
prettyPrintInput(input);
return defineConfig({
build: {
rollupOptions: {
input, // this will be deep-merged into the current config
},
},
});
},
});
export default vitePluginDetectInput;