extension-develop 3.15.1 → 3.16.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/0~branding.mjs +26 -0
- package/dist/0~dev-server.mjs +488 -0
- package/dist/0~rslib-runtime.mjs +40 -0
- package/dist/0~rspack-config.mjs +8648 -0
- package/dist/0~stats-handler.mjs +25 -0
- package/dist/0~zip.mjs +34 -0
- package/dist/314.mjs +35 -0
- package/dist/526.mjs +23 -0
- package/dist/946.mjs +1670 -0
- package/dist/962.mjs +1389 -0
- package/dist/ensure-hmr-for-scripts.js +12 -56
- package/dist/{ensure-hmr-for-scripts.cjs → ensure-hmr-for-scripts.mjs} +12 -56
- package/dist/feature-scripts-content-script-wrapper.js +23 -98
- package/dist/{feature-scripts-content-script-wrapper.cjs → feature-scripts-content-script-wrapper.mjs} +23 -98
- package/dist/main-world-bridge.js +0 -18
- package/dist/{main-world-bridge.cjs → main-world-bridge.mjs} +0 -18
- package/dist/minimum-chromium-file.js +0 -5
- package/dist/minimum-chromium-file.mjs +5 -0
- package/dist/minimum-firefox-file.js +0 -5
- package/dist/minimum-firefox-file.mjs +5 -0
- package/dist/minimum-script-file.js +0 -18
- package/dist/{minimum-script-file.cjs → minimum-script-file.mjs} +0 -18
- package/dist/module.mjs +3 -0
- package/dist/package.json +1 -1
- package/dist/preact-refresh-shim.mjs +7 -0
- package/dist/preview.mjs +2 -0
- package/dist/resolve-paths-loader.js +1043 -1093
- package/dist/resolve-paths-loader.mjs +1300 -0
- package/package.json +8 -8
- package/dist/221.cjs +0 -513
- package/dist/442.cjs +0 -9226
- package/dist/504.cjs +0 -65
- package/dist/787.cjs +0 -44
- package/dist/minimum-chromium-file.cjs +0 -10
- package/dist/minimum-firefox-file.cjs +0 -10
- package/dist/module.cjs +0 -3479
- package/dist/preact-refresh-shim.cjs +0 -25
- package/dist/preview.cjs +0 -1464
- package/dist/resolve-paths-loader.cjs +0 -1350
package/dist/946.mjs
ADDED
|
@@ -0,0 +1,1670 @@
|
|
|
1
|
+
import { createRequire as __extjsCreateRequire } from "node:module"; const require = __extjsCreateRequire(import.meta.url);
|
|
2
|
+
import pintor from "pintor";
|
|
3
|
+
import { pathToFileURL } from "url";
|
|
4
|
+
import { createRequire } from "module";
|
|
5
|
+
import dotenv from "dotenv";
|
|
6
|
+
import { fetchExtensionFromStore } from "extension-from-store";
|
|
7
|
+
import path_0 from "path";
|
|
8
|
+
import { getSpecialFoldersData } from "browser-extension-manifest-fields";
|
|
9
|
+
import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
|
|
10
|
+
import { dirname as __rspack_dirname } from "node:path";
|
|
11
|
+
import * as __rspack_external_path from "path";
|
|
12
|
+
import * as __rspack_external_fs from "fs";
|
|
13
|
+
import * as __rspack_external_os from "os";
|
|
14
|
+
import * as __rspack_external_vm from "vm";
|
|
15
|
+
var package_namespaceObject = JSON.parse('{"rE":"3.16.0","El":{"@prefresh/core":"1.5.9","@prefresh/utils":"1.2.1","@rspack/core":"^2.0.1","@rspack/dev-server":"^2.0.1","@rspack/plugin-preact-refresh":"1.1.5","@rspack/plugin-react-refresh":"1.6.2","@swc/core":"^1.15.8","@swc/helpers":"^0.5.18","@vue/compiler-sfc":"3.5.26","adm-zip":"^0.5.16","browser-extension-manifest-fields":"^2.2.3","case-sensitive-paths-webpack-plugin":"^2.4.0","content-security-policy-parser":"^0.6.0","cross-spawn":"^7.0.6","dotenv":"^17.2.3","extension-from-store":"^0.1.1","go-git-it":"^5.1.5","ignore":"^7.0.5","less":"4.5.1","less-loader":"12.3.2","loader-utils":"^3.3.1","magic-string":"^0.30.21","parse5-utilities":"^1.0.0","pintor":"0.3.0","postcss":"8.5.10","postcss-loader":"8.2.1","postcss-preset-env":"11.1.1","postcss-scss":"4.0.9","preact":"10.27.3","react-refresh":"0.18.0","sass-loader":"16.0.7","schema-utils":"^4.3.3","svelte-loader":"3.2.4","tiny-glob":"^0.2.9","typescript":"5.9.3","unique-names-generator":"^4.7.1","vue":"3.5.26","vue-loader":"17.4.2","webextension-polyfill":"^0.12.0","webpack-merge":"^6.0.1","webpack-target-webextension":"^2.1.3"}}');
|
|
16
|
+
const fmt = {
|
|
17
|
+
heading: (title)=>pintor.underline(pintor.blue(title)),
|
|
18
|
+
label: (key)=>pintor.gray(key.toUpperCase()),
|
|
19
|
+
val: (value)=>pintor.underline(value),
|
|
20
|
+
code: (value)=>pintor.blue(value),
|
|
21
|
+
bullet: (value)=>`- ${value}`,
|
|
22
|
+
block (title, rows) {
|
|
23
|
+
const head = fmt.heading(title);
|
|
24
|
+
const body = rows.map(([key, value])=>`${fmt.label(key)} ${value}`).join('\n');
|
|
25
|
+
return `${head}\n${body}`;
|
|
26
|
+
},
|
|
27
|
+
truncate (input, max = 800) {
|
|
28
|
+
const s = (()=>{
|
|
29
|
+
try {
|
|
30
|
+
return 'string' == typeof input ? input : JSON.stringify(input);
|
|
31
|
+
} catch {
|
|
32
|
+
return String(input);
|
|
33
|
+
}
|
|
34
|
+
})();
|
|
35
|
+
return s.length > max ? s.slice(0, max) + '…' : s;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function getLoggingPrefix(type) {
|
|
39
|
+
const isAuthor = 'true' === process.env.EXTENSION_AUTHOR_MODE;
|
|
40
|
+
if (isAuthor) {
|
|
41
|
+
const base = 'error' === type ? 'ERROR Author says' : '⏵⏵⏵ Author says';
|
|
42
|
+
return pintor.brightMagenta(base);
|
|
43
|
+
}
|
|
44
|
+
if ('error' === type) return pintor.red('ERROR');
|
|
45
|
+
if ('warn' === type) return pintor.brightYellow('⏵⏵⏵');
|
|
46
|
+
if ('info' === type) return pintor.gray('⏵⏵⏵');
|
|
47
|
+
return pintor.green('⏵⏵⏵');
|
|
48
|
+
}
|
|
49
|
+
function isPathLike(input) {
|
|
50
|
+
return input.includes('/') || input.includes('\\') || __rspack_external_path.isAbsolute(input);
|
|
51
|
+
}
|
|
52
|
+
function manifestNotFoundError(manifestPath) {
|
|
53
|
+
return `${getLoggingPrefix('error')} Manifest file not found.\n${pintor.red('Ensure the path to your extension exists and try again.')}\n${pintor.red('NOT FOUND')}\n${pintor.gray('PATH')} ${pintor.underline(manifestPath)}`;
|
|
54
|
+
}
|
|
55
|
+
function previewing(browser) {
|
|
56
|
+
return `${getLoggingPrefix('info')} Previewing the extension on ${capitalizedBrowserName(browser)}...`;
|
|
57
|
+
}
|
|
58
|
+
function previewSkippedNoBrowser(browser) {
|
|
59
|
+
return `${getLoggingPrefix('info')} Skipping browser launch for ${capitalizedBrowserName(browser)} (no-browser).`;
|
|
60
|
+
}
|
|
61
|
+
function authorInstallNotice(target) {
|
|
62
|
+
return `${getLoggingPrefix('warn')} Author mode: installing ${target}.`;
|
|
63
|
+
}
|
|
64
|
+
function buildWebpack(projectDir, stats, browser) {
|
|
65
|
+
const statsJson = stats?.toJson({
|
|
66
|
+
all: false,
|
|
67
|
+
assets: true,
|
|
68
|
+
time: true
|
|
69
|
+
});
|
|
70
|
+
const outputPath = 'string' == typeof stats?.compilation?.outputOptions?.path ? stats.compilation.outputOptions.path : '';
|
|
71
|
+
const manifestPath = outputPath ? __rspack_external_path.join(outputPath, 'manifest.json') : __rspack_external_path.join(projectDir, 'manifest.json');
|
|
72
|
+
const manifest = JSON.parse(__rspack_external_fs.readFileSync(manifestPath, 'utf8'));
|
|
73
|
+
const assets = statsJson?.assets;
|
|
74
|
+
const heading = `${getLoggingPrefix('info')} Building ${pintor.blue(manifest.name)} extension using ${capitalizedBrowserName(browser)} defaults...\n`;
|
|
75
|
+
const buildTime = `\nBuild completed in ${((statsJson?.time || 0) / 1000).toFixed(2)} seconds.\n`;
|
|
76
|
+
const buildTarget = `Build Target: ${pintor.gray(capitalizedBrowserName(browser))}\n`;
|
|
77
|
+
const buildStatus = `Build Status: ${stats?.hasErrors() ? pintor.red('Failed') : pintor.green('Success')}\n`;
|
|
78
|
+
const version = `\nVersion: ${pintor.gray(manifest.version)}\n`;
|
|
79
|
+
const size = `Size: ${pintor.gray(getAssetsSize(assets))}\n`;
|
|
80
|
+
let output = '';
|
|
81
|
+
output += heading;
|
|
82
|
+
output += getAssetsTree(assets);
|
|
83
|
+
output += version;
|
|
84
|
+
output += size;
|
|
85
|
+
output += buildTarget;
|
|
86
|
+
output += buildStatus;
|
|
87
|
+
output += buildTime;
|
|
88
|
+
return output;
|
|
89
|
+
}
|
|
90
|
+
function buildSuccess() {
|
|
91
|
+
return `${getLoggingPrefix('success')} Build succeeded with no warnings. Your extension is ${pintor.green('ready for deployment')}.`;
|
|
92
|
+
}
|
|
93
|
+
function getWarningMessage(warning) {
|
|
94
|
+
if (!warning) return '';
|
|
95
|
+
if ('string' == typeof warning) return warning.trim();
|
|
96
|
+
const candidates = [
|
|
97
|
+
warning.message,
|
|
98
|
+
warning.details,
|
|
99
|
+
warning.reason,
|
|
100
|
+
warning.description
|
|
101
|
+
];
|
|
102
|
+
for (const candidate of candidates)if ('string' == typeof candidate && candidate.trim()) return candidate.trim();
|
|
103
|
+
return '';
|
|
104
|
+
}
|
|
105
|
+
function getWarningSource(warning) {
|
|
106
|
+
if (!warning || 'string' == typeof warning) return 'bundler';
|
|
107
|
+
const candidates = [
|
|
108
|
+
warning.name,
|
|
109
|
+
warning.moduleName,
|
|
110
|
+
warning.moduleIdentifier,
|
|
111
|
+
warning.originName,
|
|
112
|
+
warning.pluginName
|
|
113
|
+
];
|
|
114
|
+
for (const candidate of candidates)if ('string' == typeof candidate && candidate.trim()) return candidate.trim();
|
|
115
|
+
return 'bundler';
|
|
116
|
+
}
|
|
117
|
+
function getWarningArtifact(warning) {
|
|
118
|
+
if (!warning || 'string' == typeof warning) return '';
|
|
119
|
+
const candidates = [
|
|
120
|
+
warning.file,
|
|
121
|
+
warning.chunkName,
|
|
122
|
+
warning.moduleName
|
|
123
|
+
];
|
|
124
|
+
for (const candidate of candidates)if ('string' == typeof candidate && candidate.trim()) return candidate.trim();
|
|
125
|
+
return '';
|
|
126
|
+
}
|
|
127
|
+
function classifyWarning(message, source) {
|
|
128
|
+
const haystack = `${message} ${source}`.toLowerCase();
|
|
129
|
+
if (haystack.includes('performance') || haystack.includes('asset size') || haystack.includes('entrypoint size') || haystack.includes('exceeds the recommended size') || haystack.includes('hints')) return 'Performance';
|
|
130
|
+
if (haystack.includes('deprecat') || haystack.includes('[dep_') || haystack.includes('legacy')) return 'Deprecation';
|
|
131
|
+
if (haystack.includes('invalid') || haystack.includes('unknown option') || haystack.includes('configuration') || haystack.includes('schema')) return 'Configuration';
|
|
132
|
+
if (haystack.includes('manifest') || haystack.includes('browser') || haystack.includes('target')) return 'Compatibility';
|
|
133
|
+
if (haystack.includes('runtime') || haystack.includes('will fail') || haystack.includes('cannot resolve') || haystack.includes('service_worker')) return 'Runtime-risk';
|
|
134
|
+
return 'Warning';
|
|
135
|
+
}
|
|
136
|
+
function suggestedHintForWarning(category) {
|
|
137
|
+
if ('Performance' === category) return 'Inspect the largest startup bundles and split optional code paths.';
|
|
138
|
+
if ('Deprecation' === category) return 'Move to the supported API or plugin path before the next update.';
|
|
139
|
+
if ('Configuration' === category) return 'Review extension and bundler config keys, then remove or rename invalid options.';
|
|
140
|
+
if ('Compatibility' === category) return 'Verify browser target and manifest compatibility for this build.';
|
|
141
|
+
if ('Runtime-risk' === category) return 'Address this before release; it may fail or degrade at runtime.';
|
|
142
|
+
return 'Re-run with EXTENSION_VERBOSE=1 to inspect full warning details.';
|
|
143
|
+
}
|
|
144
|
+
function buildSuccessWithWarnings(warningCount) {
|
|
145
|
+
return `${getLoggingPrefix('warn')} Build succeeded with ${warningCount} warning(s). Your extension is ${pintor.green('ready for deployment')}.`;
|
|
146
|
+
}
|
|
147
|
+
function buildWarningsDetails(warnings) {
|
|
148
|
+
if (!Array.isArray(warnings) || 0 === warnings.length) return '';
|
|
149
|
+
const blocks = [];
|
|
150
|
+
warnings.forEach((warning, index)=>{
|
|
151
|
+
const message = getWarningMessage(warning);
|
|
152
|
+
const source = getWarningSource(warning);
|
|
153
|
+
const artifact = getWarningArtifact(warning);
|
|
154
|
+
const category = classifyWarning(message, source);
|
|
155
|
+
const hint = suggestedHintForWarning(category);
|
|
156
|
+
if (!message) return void blocks.push(`${getLoggingPrefix('warn')} Warning ${index + 1}: details were suppressed by tool output.\n${formatWarningLabelLine('Source', pintor.gray(source))}\n${formatWarningLabelLine('Hint', 'Re-run with EXTENSION_VERBOSE=1 to inspect full warning messages.')}`);
|
|
157
|
+
const performanceWarning = parsePerformanceWarning(warning, source, artifact);
|
|
158
|
+
if (performanceWarning) return void blocks.push(performanceWarning);
|
|
159
|
+
const oneLine = message.replace(/\s+/g, ' ').trim();
|
|
160
|
+
const artifactSuffix = artifact ? ` ${pintor.gray(`(${artifact})`)}` : '';
|
|
161
|
+
blocks.push(`${getLoggingPrefix('warn')} ${category}: ${oneLine}${artifactSuffix}\n${formatWarningLabelLine('Source', pintor.gray(source))}\n${formatWarningLabelLine('Hint', hint)}`);
|
|
162
|
+
});
|
|
163
|
+
return blocks.join('\n\n');
|
|
164
|
+
}
|
|
165
|
+
function fetchingProjectPath(owner, project) {
|
|
166
|
+
return fmt.block('Fetching project', [
|
|
167
|
+
[
|
|
168
|
+
'URL',
|
|
169
|
+
fmt.val(`https://github.com/${owner}/${project}`)
|
|
170
|
+
]
|
|
171
|
+
]);
|
|
172
|
+
}
|
|
173
|
+
function downloadingProjectPath(projectName) {
|
|
174
|
+
const formatted = isPathLike(projectName) ? pintor.underline(projectName) : pintor.yellow(projectName);
|
|
175
|
+
return `${getLoggingPrefix('info')} Downloading ${formatted}...`;
|
|
176
|
+
}
|
|
177
|
+
function creatingProjectPath(projectPath) {
|
|
178
|
+
return `${getLoggingPrefix('info')} Creating a new browser extension...\n${pintor.gray('PATH')} ${pintor.underline(projectPath)}`;
|
|
179
|
+
}
|
|
180
|
+
function downloadedProjectFolderNotFound(cwd, candidates) {
|
|
181
|
+
return `${getLoggingPrefix('error')} Downloaded project folder not found.\n${pintor.gray('PATH')} ${pintor.underline(cwd)}\n${pintor.gray('Tried')} ${pintor.underline(candidates.join(', '))}`;
|
|
182
|
+
}
|
|
183
|
+
function packagingSourceFiles(zipPath) {
|
|
184
|
+
return `${getLoggingPrefix('info')} Packaging source files. Files in ${pintor.yellow('.gitignore')} will be excluded...\n${pintor.gray('PATH')} ${pintor.underline(zipPath)}.`;
|
|
185
|
+
}
|
|
186
|
+
function packagingDistributionFiles(zipPath) {
|
|
187
|
+
return `${getLoggingPrefix('info')} Packaging extension distribution files...\n${pintor.gray('PATH')} ${pintor.underline(zipPath)}`;
|
|
188
|
+
}
|
|
189
|
+
function treeWithSourceAndDistFiles(browser, name, sourceZip, destZip) {
|
|
190
|
+
return `📦 Package name: ${pintor.blue(`${name}`)}, Target Browser: ${capitalizedBrowserName(browser)}\n ${pintor.gray('└─')} ${pintor.underline(`${sourceZip}`)} ${pintor.gray('(source)')}\n ${pintor.gray('└─')} ${pintor.underline(`${destZip}`)} ${pintor.gray('(distribution)')}`;
|
|
191
|
+
}
|
|
192
|
+
function treeWithDistFilesbrowser(name, ext, browser, zipPath) {
|
|
193
|
+
return `📦 Package name: ${pintor.blue(`${name}.${ext}`)}, Target Browser: ${capitalizedBrowserName(browser)}\n ${pintor.gray('└─')} ${pintor.underline(`${zipPath}`)} ${pintor.gray('(distribution)')}`;
|
|
194
|
+
}
|
|
195
|
+
function treeWithSourceFiles(name, ext, browser, zipPath) {
|
|
196
|
+
return `📦 Package name: ${pintor.blue(`${name}-source.${ext}`)}, Target Browser: ${capitalizedBrowserName(browser)}\n ${pintor.gray('└─')} ${pintor.underline(`${zipPath}`)} ${pintor.gray('(source)')}`;
|
|
197
|
+
}
|
|
198
|
+
function writingTypeDefinitions(manifest) {
|
|
199
|
+
return `${getLoggingPrefix('info')} Writing type definitions for ${pintor.blue(manifest.name || '')}...`;
|
|
200
|
+
}
|
|
201
|
+
function writingTypeDefinitionsError(error) {
|
|
202
|
+
return `${getLoggingPrefix('error')} Failed to write the extension type definition.\n${pintor.red(error)}`;
|
|
203
|
+
}
|
|
204
|
+
function downloadingText(url) {
|
|
205
|
+
return fmt.block('Downloading extension', [
|
|
206
|
+
[
|
|
207
|
+
'URL',
|
|
208
|
+
fmt.val(url)
|
|
209
|
+
]
|
|
210
|
+
]);
|
|
211
|
+
}
|
|
212
|
+
function unpackagingExtension(zipFilePath) {
|
|
213
|
+
return `${getLoggingPrefix('info')} Unpackaging browser extension...\n${pintor.gray('PATH')} ${pintor.underline(zipFilePath)}`;
|
|
214
|
+
}
|
|
215
|
+
function unpackagedSuccessfully() {
|
|
216
|
+
return `${getLoggingPrefix('info')} Browser extension unpackaged ${pintor.green('successfully')}.`;
|
|
217
|
+
}
|
|
218
|
+
function failedToDownloadOrExtractZIPFileError(error) {
|
|
219
|
+
return `${getLoggingPrefix('error')} Failed to download or extract ZIP file.\n${pintor.red(error)}`;
|
|
220
|
+
}
|
|
221
|
+
function invalidRemoteZip(url, contentType) {
|
|
222
|
+
return `${getLoggingPrefix('error')} Remote URL does not appear to be a ZIP archive.\n${pintor.gray('URL')} ${pintor.underline(url)}\n${pintor.gray('Content-Type')} ${pintor.underline(contentType || 'unknown')}`;
|
|
223
|
+
}
|
|
224
|
+
function capitalizedBrowserName(browser) {
|
|
225
|
+
const b = String(browser || '');
|
|
226
|
+
const cap = b.charAt(0).toUpperCase() + b.slice(1);
|
|
227
|
+
return pintor.yellow(`${cap}`);
|
|
228
|
+
}
|
|
229
|
+
function getFileSize(fileSizeInBytes) {
|
|
230
|
+
return `${(fileSizeInBytes / 1024).toFixed(2)}KB`;
|
|
231
|
+
}
|
|
232
|
+
function getAssetsSize(assets) {
|
|
233
|
+
let totalSize = 0;
|
|
234
|
+
assets?.forEach((asset)=>{
|
|
235
|
+
totalSize += asset.size;
|
|
236
|
+
});
|
|
237
|
+
return getFileSize(totalSize);
|
|
238
|
+
}
|
|
239
|
+
function printTree(node, prefix = '') {
|
|
240
|
+
let output = '';
|
|
241
|
+
Object.keys(node).forEach((key, index, array)=>{
|
|
242
|
+
const isLast = index === array.length - 1;
|
|
243
|
+
const connector = isLast ? '└─' : '├─';
|
|
244
|
+
const sizeInKB = node[key].size ? ` (${getFileSize(node[key].size)})` : '';
|
|
245
|
+
output += `${pintor.gray(prefix)}${pintor.gray(connector)} ${key}${pintor.gray(sizeInKB)}\n`;
|
|
246
|
+
if ('object' == typeof node[key] && !node[key].size) output += printTree(node[key], `${prefix}${isLast ? ' ' : pintor.gray('│ ')}`);
|
|
247
|
+
});
|
|
248
|
+
return output;
|
|
249
|
+
}
|
|
250
|
+
function getAssetsTree(assets) {
|
|
251
|
+
const assetTree = {};
|
|
252
|
+
assets?.forEach((asset)=>{
|
|
253
|
+
const paths = asset.name.split('/');
|
|
254
|
+
let currentLevel = assetTree;
|
|
255
|
+
paths.forEach((part, index)=>{
|
|
256
|
+
if (!currentLevel[part]) currentLevel[part] = {};
|
|
257
|
+
if (index === paths.length - 1) currentLevel[part] = {
|
|
258
|
+
size: asset.size
|
|
259
|
+
};
|
|
260
|
+
else currentLevel = currentLevel[part];
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
return `.\n${printTree(assetTree)}`;
|
|
264
|
+
}
|
|
265
|
+
function formatWarningLabelLine(label, value) {
|
|
266
|
+
return `${pintor.gray('│')} ${pintor.gray(`${label}:`)} ${value}`;
|
|
267
|
+
}
|
|
268
|
+
function parsePerformanceWarning(warning, source, _artifact) {
|
|
269
|
+
const normalized = getWarningBody(warning).replace(/\r/g, '');
|
|
270
|
+
const lower = normalized.toLowerCase();
|
|
271
|
+
const threshold = normalized.match(/\(([\d.]+\s(?:KiB|MiB|GiB|KB|MB|GB))\)/)?.[1] || '';
|
|
272
|
+
if (lower.includes('asset size limit')) return formatPerformanceWarningBlock({
|
|
273
|
+
title: 'asset size limit exceeded',
|
|
274
|
+
threshold,
|
|
275
|
+
impact: 'Large emitted files can increase package size and slow extension startup.',
|
|
276
|
+
source,
|
|
277
|
+
hint: 'Inspect the largest startup bundles and split optional code paths.'
|
|
278
|
+
});
|
|
279
|
+
if (lower.includes('entrypoint size limit')) return formatPerformanceWarningBlock({
|
|
280
|
+
title: 'entrypoint size limit exceeded',
|
|
281
|
+
threshold,
|
|
282
|
+
impact: 'Startup entrypoints are heavier than recommended.',
|
|
283
|
+
source,
|
|
284
|
+
hint: 'Keep startup entrypoints thin and defer non-critical code.'
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
function formatPerformanceWarningBlock(options) {
|
|
288
|
+
const lines = [
|
|
289
|
+
`${getLoggingPrefix('warn')} Performance: ${options.title}`
|
|
290
|
+
];
|
|
291
|
+
if (options.threshold) lines.push(formatWarningLabelLine('Threshold', options.threshold));
|
|
292
|
+
lines.push(formatWarningLabelLine('Impact', options.impact));
|
|
293
|
+
lines.push(pintor.gray('│'));
|
|
294
|
+
lines.push(formatWarningLabelLine('Source', pintor.gray(options.source)));
|
|
295
|
+
lines.push(formatWarningLabelLine('Hint', options.hint));
|
|
296
|
+
return lines.join('\n');
|
|
297
|
+
}
|
|
298
|
+
function getWarningBody(warning) {
|
|
299
|
+
if (!warning) return '';
|
|
300
|
+
if ('string' == typeof warning) return warning;
|
|
301
|
+
return [
|
|
302
|
+
warning.message,
|
|
303
|
+
warning.details,
|
|
304
|
+
warning.reason,
|
|
305
|
+
warning.description
|
|
306
|
+
].filter((value)=>'string' == typeof value && value.trim().length > 0).join('\n');
|
|
307
|
+
}
|
|
308
|
+
function isUsingExperimentalConfig(integration) {
|
|
309
|
+
return `${getLoggingPrefix('info')} Using ${pintor.yellow(integration)}.`;
|
|
310
|
+
}
|
|
311
|
+
function debugDirs(manifestDir, packageJsonDir) {
|
|
312
|
+
return `${getLoggingPrefix('info')} Directories\n${pintor.gray('MANIFEST_DIR')} ${pintor.underline(manifestDir)}\n${pintor.gray('PACKAGE_JSON_DIR')} ${pintor.underline(packageJsonDir)}`;
|
|
313
|
+
}
|
|
314
|
+
function debugBrowser(browser, chromiumBinary, geckoBinary) {
|
|
315
|
+
return `${getLoggingPrefix('info')} Browser Target\n${pintor.gray('BROWSER')} ${pintor.yellow(String(browser))}\n${pintor.gray('CHROMIUM_BINARY')} ${pintor.underline(String(chromiumBinary || 'auto'))}\n${pintor.gray('GECKO_BINARY')} ${pintor.underline(String(geckoBinary || 'auto'))}`;
|
|
316
|
+
}
|
|
317
|
+
function debugOutputPath(pathValue) {
|
|
318
|
+
return `${getLoggingPrefix('info')} Output Path\n${pintor.gray('PATH')} ${pintor.underline(pathValue)}`;
|
|
319
|
+
}
|
|
320
|
+
function debugPreviewOutput(outputPath, distPath) {
|
|
321
|
+
return `${getLoggingPrefix('info')} Preview Output\n${pintor.gray('OUTPUT')} ${pintor.underline(outputPath)}\n${pintor.gray('DIST')} ${pintor.underline(distPath)}`;
|
|
322
|
+
}
|
|
323
|
+
function debugContextPath(packageJsonDir) {
|
|
324
|
+
return `${getLoggingPrefix('info')} Context\n${pintor.gray('CONTEXT')} ${pintor.underline(packageJsonDir)}`;
|
|
325
|
+
}
|
|
326
|
+
function debugExtensionsToLoad(extensions) {
|
|
327
|
+
const header = `${getLoggingPrefix('info')} Extensions To Load (${extensions.length})`;
|
|
328
|
+
const list = extensions.map((e)=>`- ${pintor.underline(e)}`).join('\n');
|
|
329
|
+
return `${header}\n${list}`;
|
|
330
|
+
}
|
|
331
|
+
function noCompanionExtensionsResolved() {
|
|
332
|
+
return `${getLoggingPrefix('warn')} No companion extensions resolved from ${pintor.underline('extensions')} config.\n${pintor.gray('Ensure each companion extension is an unpacked extension directory containing a manifest.json (e.g., ./extensions/<name>/manifest.json).')}`;
|
|
333
|
+
}
|
|
334
|
+
function configLoadingError(configPath, error) {
|
|
335
|
+
return `${pintor.red('ERROR')} ${pintor.brightBlue('config load failed')}\n${fmt.label('PATH')} ${fmt.val(configPath)}\n` + pintor.red(fmt.truncate(error, 1200));
|
|
336
|
+
}
|
|
337
|
+
function buildCommandFailed(error) {
|
|
338
|
+
const message = (()=>{
|
|
339
|
+
if (error instanceof Error && error.message) return error.message;
|
|
340
|
+
return String(error || 'Unknown error');
|
|
341
|
+
})();
|
|
342
|
+
return `${getLoggingPrefix('error')} Build failed.\n${pintor.red(fmt.truncate(message, 1200))}`;
|
|
343
|
+
}
|
|
344
|
+
function managedDependencyConflict(duplicates, userPackageJsonPath) {
|
|
345
|
+
const list = duplicates.map((d)=>`- ${pintor.yellow(d)}`).join('\n');
|
|
346
|
+
return `${getLoggingPrefix('error')} Your project declares dependencies that are managed by ${pintor.blue('Extension.js')} and referenced in ${pintor.underline('extension.config.js')}\n${pintor.red('This can cause version conflicts and break the development/build process.')}\n\n${pintor.gray('Managed dependencies (remove these from your package.json):')}\n${list}\n\n${pintor.gray('PATH')} ${pintor.underline(userPackageJsonPath)}\nIf you need a different version, open an issue so we can consider bundling it safely.\nOperation aborted.`;
|
|
347
|
+
}
|
|
348
|
+
async function findUpLocal(filename, options) {
|
|
349
|
+
const root = __rspack_external_path.parse(options.cwd).root;
|
|
350
|
+
let currentDir = options.cwd;
|
|
351
|
+
while(true){
|
|
352
|
+
const candidate = __rspack_external_path.join(currentDir, filename);
|
|
353
|
+
try {
|
|
354
|
+
const stat = await __rspack_external_fs.promises.stat(candidate);
|
|
355
|
+
if (stat.isFile()) return candidate;
|
|
356
|
+
} catch {}
|
|
357
|
+
if (currentDir === root) return;
|
|
358
|
+
currentDir = __rspack_external_path.dirname(currentDir);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
async function findNearestPackageJson(manifestPath) {
|
|
362
|
+
try {
|
|
363
|
+
const manifestDir = __rspack_external_path.dirname(manifestPath);
|
|
364
|
+
const packageJsonPath = await findUpLocal('package.json', {
|
|
365
|
+
cwd: manifestDir
|
|
366
|
+
});
|
|
367
|
+
return packageJsonPath || null;
|
|
368
|
+
} catch (error) {
|
|
369
|
+
console.warn('Failed to find package.json:', error);
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function validatePackageJson(packageJsonPath) {
|
|
374
|
+
try {
|
|
375
|
+
if (!__rspack_external_fs.existsSync(packageJsonPath)) return false;
|
|
376
|
+
const content = __rspack_external_fs.readFileSync(packageJsonPath, 'utf-8');
|
|
377
|
+
JSON.parse(content);
|
|
378
|
+
return true;
|
|
379
|
+
} catch (error) {
|
|
380
|
+
console.warn('Invalid package.json at:', packageJsonPath, error);
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
const isUrl = (url)=>{
|
|
385
|
+
try {
|
|
386
|
+
new URL(url);
|
|
387
|
+
return true;
|
|
388
|
+
} catch (e) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
async function importUrlSourceFromGithub(pathOrRemoteUrl, text) {
|
|
393
|
+
const cwd = process.cwd();
|
|
394
|
+
const url = new URL(pathOrRemoteUrl);
|
|
395
|
+
const segments = url.pathname.split('/').filter(Boolean);
|
|
396
|
+
const repoName = segments.length >= 2 ? segments[1] : segments[segments.length - 1];
|
|
397
|
+
const treeIndex = segments.indexOf('tree');
|
|
398
|
+
const expectedName = -1 !== treeIndex && segments.length > treeIndex + 2 ? segments[segments.length - 1] : repoName;
|
|
399
|
+
const expectedPath = __rspack_external_path.resolve(cwd, expectedName);
|
|
400
|
+
if (__rspack_external_fs.existsSync(expectedPath)) try {
|
|
401
|
+
const entries = __rspack_external_fs.readdirSync(expectedPath);
|
|
402
|
+
if (0 === entries.length) __rspack_external_fs.rmSync(expectedPath, {
|
|
403
|
+
recursive: true,
|
|
404
|
+
force: true
|
|
405
|
+
});
|
|
406
|
+
else {
|
|
407
|
+
const hasManifest = (dir)=>{
|
|
408
|
+
const stack = [
|
|
409
|
+
dir
|
|
410
|
+
];
|
|
411
|
+
while(stack.length){
|
|
412
|
+
const current = stack.pop();
|
|
413
|
+
const items = __rspack_external_fs.readdirSync(current, {
|
|
414
|
+
withFileTypes: true
|
|
415
|
+
});
|
|
416
|
+
for (const it of items){
|
|
417
|
+
if (it.isFile() && 'manifest.json' === it.name) return true;
|
|
418
|
+
if (it.isDirectory() && 'node_modules' !== it.name && 'dist' !== it.name && !it.name.startsWith('.')) stack.push(__rspack_external_path.join(current, it.name));
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return false;
|
|
422
|
+
};
|
|
423
|
+
if (hasManifest(expectedPath)) return expectedPath;
|
|
424
|
+
__rspack_external_fs.rmSync(expectedPath, {
|
|
425
|
+
recursive: true,
|
|
426
|
+
force: true
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
} catch {}
|
|
430
|
+
async function tryGitClone() {
|
|
431
|
+
const { default: goGitIt } = await import("go-git-it");
|
|
432
|
+
await goGitIt(pathOrRemoteUrl, cwd, text);
|
|
433
|
+
}
|
|
434
|
+
async function tryZipFallback() {
|
|
435
|
+
const branch = -1 !== treeIndex && segments.length > treeIndex + 1 ? segments[treeIndex + 1] : 'main';
|
|
436
|
+
const owner = segments[0];
|
|
437
|
+
const repo = segments[1];
|
|
438
|
+
const subdir = -1 !== treeIndex && segments.length > treeIndex + 2 ? segments.slice(treeIndex + 2).join('/') : '';
|
|
439
|
+
const zipUrl = `https://codeload.github.com/${owner}/${repo}/zip/refs/heads/${branch}`;
|
|
440
|
+
const extractedPath = await importUrlSourceFromZip(zipUrl);
|
|
441
|
+
const extractedDirs = __rspack_external_fs.readdirSync(extractedPath, {
|
|
442
|
+
withFileTypes: true
|
|
443
|
+
}).filter((d)=>d.isDirectory()).map((d)=>d.name);
|
|
444
|
+
const repoRootDir = extractedDirs.find((d)=>d.startsWith(`${repo}-${branch}`));
|
|
445
|
+
const repoRoot = repoRootDir ? __rspack_external_path.join(extractedPath, repoRootDir) : extractedPath;
|
|
446
|
+
return subdir ? __rspack_external_path.join(repoRoot, subdir) : repoRoot;
|
|
447
|
+
}
|
|
448
|
+
try {
|
|
449
|
+
await tryGitClone();
|
|
450
|
+
} catch {
|
|
451
|
+
return await tryZipFallback();
|
|
452
|
+
}
|
|
453
|
+
const candidates = [];
|
|
454
|
+
if (-1 !== treeIndex && segments.length > treeIndex + 2) candidates.push(segments[segments.length - 1]);
|
|
455
|
+
candidates.push(repoName);
|
|
456
|
+
for (const name of candidates){
|
|
457
|
+
const p = __rspack_external_path.resolve(cwd, name);
|
|
458
|
+
if (__rspack_external_fs.existsSync(p)) return p;
|
|
459
|
+
}
|
|
460
|
+
const dirs = __rspack_external_fs.readdirSync(cwd, {
|
|
461
|
+
withFileTypes: true
|
|
462
|
+
}).filter((d)=>d.isDirectory()).map((d)=>d.name);
|
|
463
|
+
for (const dir of dirs){
|
|
464
|
+
const manifestPath = __rspack_external_path.join(cwd, dir, 'manifest.json');
|
|
465
|
+
if (__rspack_external_fs.existsSync(manifestPath)) return __rspack_external_path.join(cwd, dir);
|
|
466
|
+
}
|
|
467
|
+
try {
|
|
468
|
+
const dirs = __rspack_external_fs.readdirSync(cwd, {
|
|
469
|
+
withFileTypes: true
|
|
470
|
+
}).filter((d)=>d.isDirectory()).map((d)=>d.name);
|
|
471
|
+
const ghRoot = dirs.find((d)=>/-main$|-master$/.test(d));
|
|
472
|
+
if (ghRoot) return __rspack_external_path.join(cwd, ghRoot);
|
|
473
|
+
} catch {}
|
|
474
|
+
throw new Error(downloadedProjectFolderNotFound(cwd, candidates));
|
|
475
|
+
}
|
|
476
|
+
async function importUrlSourceFromZip(pathOrRemoteUrl) {
|
|
477
|
+
const cwd = process.cwd();
|
|
478
|
+
const { downloadAndExtractZip } = await import("./0~zip.mjs");
|
|
479
|
+
const extractedPath = await downloadAndExtractZip(pathOrRemoteUrl, cwd);
|
|
480
|
+
return extractedPath;
|
|
481
|
+
}
|
|
482
|
+
async function getProjectPath(pathOrRemoteUrl) {
|
|
483
|
+
if (!pathOrRemoteUrl) return process.cwd();
|
|
484
|
+
if (isUrl(pathOrRemoteUrl)) {
|
|
485
|
+
const url = new URL(pathOrRemoteUrl);
|
|
486
|
+
if (url.protocol.startsWith('http')) {
|
|
487
|
+
const pathname = url.pathname.toLowerCase();
|
|
488
|
+
if (pathname.endsWith('.zip')) return await importUrlSourceFromZip(pathOrRemoteUrl);
|
|
489
|
+
if ('https://github.com' !== url.origin) {
|
|
490
|
+
const urlSource = await importUrlSourceFromZip(pathOrRemoteUrl);
|
|
491
|
+
return urlSource;
|
|
492
|
+
}
|
|
493
|
+
const urlData = url.pathname.split('/');
|
|
494
|
+
const owner = urlData.slice(1, 3)[0];
|
|
495
|
+
const project = urlData.slice(1, 3)[1];
|
|
496
|
+
console.log(fetchingProjectPath(owner, project));
|
|
497
|
+
const projectName = __rspack_external_path.basename(url.pathname);
|
|
498
|
+
const urlSource = await importUrlSourceFromGithub(pathOrRemoteUrl, downloadingProjectPath(projectName));
|
|
499
|
+
console.log(creatingProjectPath(url.pathname));
|
|
500
|
+
return urlSource;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return __rspack_external_path.resolve(process.cwd(), pathOrRemoteUrl);
|
|
504
|
+
}
|
|
505
|
+
async function getProjectStructure(pathOrRemoteUrl) {
|
|
506
|
+
const projectPath = await getProjectPath(pathOrRemoteUrl);
|
|
507
|
+
const isUnderDir = (baseDir, candidatePath)=>{
|
|
508
|
+
const rel = __rspack_external_path.relative(baseDir, candidatePath);
|
|
509
|
+
return Boolean(rel && !rel.startsWith('..') && !__rspack_external_path.isAbsolute(rel));
|
|
510
|
+
};
|
|
511
|
+
const packageJsonPathFromProject = await findNearestPackageJson(__rspack_external_path.join(projectPath, 'manifest.json'));
|
|
512
|
+
const packageJsonDirFromProject = packageJsonPathFromProject ? __rspack_external_path.dirname(packageJsonPathFromProject) : void 0;
|
|
513
|
+
const rootManifestPath = __rspack_external_path.join(projectPath, 'manifest.json');
|
|
514
|
+
const srcManifestPath = __rspack_external_path.join(projectPath, 'src', 'manifest.json');
|
|
515
|
+
let manifestPath = __rspack_external_fs.existsSync(srcManifestPath) ? srcManifestPath : rootManifestPath;
|
|
516
|
+
if (!__rspack_external_fs.existsSync(manifestPath)) {
|
|
517
|
+
if (packageJsonDirFromProject) throw new Error(manifestNotFoundError(manifestPath));
|
|
518
|
+
const findManifest = (dir)=>{
|
|
519
|
+
const files = __rspack_external_fs.readdirSync(dir, {
|
|
520
|
+
withFileTypes: true
|
|
521
|
+
});
|
|
522
|
+
for (const file of files){
|
|
523
|
+
if (file.isFile() && 'manifest.json' === file.name) return __rspack_external_path.join(dir, file.name);
|
|
524
|
+
if (file.isDirectory() && !file.name.startsWith('.') && 'node_modules' !== file.name && 'dist' !== file.name && 'public' !== file.name) {
|
|
525
|
+
const found = findManifest(__rspack_external_path.join(dir, file.name));
|
|
526
|
+
if (found) return found;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return null;
|
|
530
|
+
};
|
|
531
|
+
const foundManifest = findManifest(projectPath);
|
|
532
|
+
if (foundManifest) manifestPath = foundManifest;
|
|
533
|
+
else throw new Error(manifestNotFoundError(manifestPath));
|
|
534
|
+
}
|
|
535
|
+
const packageJsonPath = await findNearestPackageJson(manifestPath);
|
|
536
|
+
const packageJsonDir = packageJsonPath ? __rspack_external_path.dirname(packageJsonPath) : void 0;
|
|
537
|
+
if (packageJsonDir) {
|
|
538
|
+
const publicRoot = __rspack_external_path.join(packageJsonDir, 'public');
|
|
539
|
+
if (isUnderDir(publicRoot, manifestPath)) {
|
|
540
|
+
const fallbackSrc = __rspack_external_path.join(packageJsonDir, 'src', 'manifest.json');
|
|
541
|
+
const fallbackRoot = __rspack_external_path.join(packageJsonDir, 'manifest.json');
|
|
542
|
+
if (__rspack_external_fs.existsSync(fallbackSrc)) manifestPath = fallbackSrc;
|
|
543
|
+
else if (__rspack_external_fs.existsSync(fallbackRoot)) manifestPath = fallbackRoot;
|
|
544
|
+
else throw new Error(manifestNotFoundError(fallbackRoot));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (!packageJsonPath || !validatePackageJson(packageJsonPath)) return {
|
|
548
|
+
manifestPath
|
|
549
|
+
};
|
|
550
|
+
return {
|
|
551
|
+
manifestPath,
|
|
552
|
+
packageJsonPath
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function loadCommonJsConfigWithStableDirname(absolutePath) {
|
|
556
|
+
const code = __rspack_external_fs.readFileSync(absolutePath, 'utf-8');
|
|
557
|
+
const dirname = __rspack_external_path.dirname(absolutePath);
|
|
558
|
+
const requireFn = createRequire(absolutePath);
|
|
559
|
+
const module = {
|
|
560
|
+
exports: {}
|
|
561
|
+
};
|
|
562
|
+
const exports = module.exports;
|
|
563
|
+
const wrapped = `(function (exports, require, module, __filename, __dirname) {\n${code}\n})`;
|
|
564
|
+
const fn = new __rspack_external_vm.Script(wrapped, {
|
|
565
|
+
filename: absolutePath
|
|
566
|
+
}).runInThisContext();
|
|
567
|
+
fn(exports, requireFn, module, absolutePath, dirname);
|
|
568
|
+
return module.exports?.default || module.exports;
|
|
569
|
+
}
|
|
570
|
+
function findNearestWorkspaceRoot(startDir) {
|
|
571
|
+
let current = __rspack_external_path.resolve(startDir);
|
|
572
|
+
while(true){
|
|
573
|
+
if (__rspack_external_fs.existsSync(__rspack_external_path.join(current, 'pnpm-workspace.yaml'))) return current;
|
|
574
|
+
const parent = __rspack_external_path.dirname(current);
|
|
575
|
+
if (parent === current) return;
|
|
576
|
+
current = parent;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
function preloadEnvFilesFromDir(envDir, options) {
|
|
580
|
+
let loadedAny = false;
|
|
581
|
+
try {
|
|
582
|
+
const defaultsPath = __rspack_external_path.join(envDir, '.env.defaults');
|
|
583
|
+
if (__rspack_external_fs.existsSync(defaultsPath)) {
|
|
584
|
+
dotenv.config({
|
|
585
|
+
path: defaultsPath,
|
|
586
|
+
override: Boolean(options?.override),
|
|
587
|
+
quiet: true
|
|
588
|
+
});
|
|
589
|
+
loadedAny = true;
|
|
590
|
+
}
|
|
591
|
+
const envCandidates = [
|
|
592
|
+
'.env.development',
|
|
593
|
+
'.env.local',
|
|
594
|
+
'.env'
|
|
595
|
+
];
|
|
596
|
+
for (const filename of envCandidates){
|
|
597
|
+
const filePath = __rspack_external_path.join(envDir, filename);
|
|
598
|
+
if (__rspack_external_fs.existsSync(filePath)) {
|
|
599
|
+
dotenv.config({
|
|
600
|
+
path: filePath,
|
|
601
|
+
override: Boolean(options?.override),
|
|
602
|
+
quiet: true
|
|
603
|
+
});
|
|
604
|
+
loadedAny = true;
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
} catch {}
|
|
609
|
+
return {
|
|
610
|
+
loadedAny,
|
|
611
|
+
envDir
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
function findConfigFile(projectPath) {
|
|
615
|
+
const candidates = [
|
|
616
|
+
__rspack_external_path.join(projectPath, 'extension.config.js'),
|
|
617
|
+
__rspack_external_path.join(projectPath, 'extension.config.mjs'),
|
|
618
|
+
__rspack_external_path.join(projectPath, 'extension.config.cjs')
|
|
619
|
+
];
|
|
620
|
+
return candidates.find((p)=>__rspack_external_fs.existsSync(p));
|
|
621
|
+
}
|
|
622
|
+
function preloadEnvFiles(projectDir) {
|
|
623
|
+
const local = preloadEnvFilesFromDir(projectDir);
|
|
624
|
+
if (local.loadedAny) return local;
|
|
625
|
+
const workspaceRoot = findNearestWorkspaceRoot(projectDir);
|
|
626
|
+
if (workspaceRoot && workspaceRoot !== projectDir) return preloadEnvFilesFromDir(workspaceRoot);
|
|
627
|
+
return local;
|
|
628
|
+
}
|
|
629
|
+
async function loadConfigFile(configPath) {
|
|
630
|
+
const absolutePath = __rspack_external_path.resolve(configPath);
|
|
631
|
+
const projectDir = __rspack_external_path.dirname(absolutePath);
|
|
632
|
+
preloadEnvFiles(projectDir);
|
|
633
|
+
try {
|
|
634
|
+
if (absolutePath.endsWith('.cjs')) {
|
|
635
|
+
const requireFn = createRequire(import.meta.url);
|
|
636
|
+
const required = requireFn(absolutePath);
|
|
637
|
+
return required?.default || required;
|
|
638
|
+
}
|
|
639
|
+
let esmImportPath = absolutePath;
|
|
640
|
+
try {
|
|
641
|
+
const originalContent = __rspack_external_fs.readFileSync(absolutePath, 'utf-8');
|
|
642
|
+
if (originalContent.includes('import.meta.env')) {
|
|
643
|
+
const tmpDir = __rspack_external_fs.mkdtempSync(__rspack_external_path.join(__rspack_external_os.tmpdir(), 'extension-config-esm-'));
|
|
644
|
+
const tmpPath = __rspack_external_path.join(tmpDir, __rspack_external_path.basename(absolutePath));
|
|
645
|
+
const envObjectLiteral = JSON.stringify(Object.fromEntries(Object.entries(process.env).map(([k, v])=>[
|
|
646
|
+
k,
|
|
647
|
+
v
|
|
648
|
+
])), null, 0);
|
|
649
|
+
const shimHeader = `const __IMPORT_META_ENV__ = Object.freeze(${envObjectLiteral});\n`;
|
|
650
|
+
const replaced = originalContent.replace(/import\.meta\.env/g, '__IMPORT_META_ENV__');
|
|
651
|
+
__rspack_external_fs.writeFileSync(tmpPath, `${shimHeader}${replaced}`, 'utf-8');
|
|
652
|
+
esmImportPath = tmpPath;
|
|
653
|
+
}
|
|
654
|
+
} catch {}
|
|
655
|
+
const module = await import(pathToFileURL(esmImportPath).href);
|
|
656
|
+
return module.default || module;
|
|
657
|
+
} catch (err) {
|
|
658
|
+
const error = err;
|
|
659
|
+
try {
|
|
660
|
+
if (!absolutePath.endsWith('.mjs')) {
|
|
661
|
+
const requireFn = createRequire(import.meta.url);
|
|
662
|
+
let required;
|
|
663
|
+
try {
|
|
664
|
+
required = requireFn(absolutePath);
|
|
665
|
+
} catch (requireErr) {
|
|
666
|
+
const message = String(error?.message || '') + ' ' + String(requireErr?.message || '');
|
|
667
|
+
const looksLikeCommonJsInEsm = message.includes('require is not defined in ES module scope') || message.includes('Cannot use import statement outside a module') || message.includes('ERR_REQUIRE_ESM');
|
|
668
|
+
if (looksLikeCommonJsInEsm) try {
|
|
669
|
+
required = loadCommonJsConfigWithStableDirname(absolutePath);
|
|
670
|
+
} catch {
|
|
671
|
+
const tmpDir = __rspack_external_fs.mkdtempSync(__rspack_external_path.join(__rspack_external_os.tmpdir(), 'extension-config-'));
|
|
672
|
+
const tmpCjsPath = __rspack_external_path.join(tmpDir, __rspack_external_path.basename(absolutePath, __rspack_external_path.extname(absolutePath)) + '.cjs');
|
|
673
|
+
__rspack_external_fs.copyFileSync(absolutePath, tmpCjsPath);
|
|
674
|
+
required = requireFn(tmpCjsPath);
|
|
675
|
+
}
|
|
676
|
+
else throw requireErr;
|
|
677
|
+
}
|
|
678
|
+
return required?.default || required;
|
|
679
|
+
}
|
|
680
|
+
} catch {}
|
|
681
|
+
try {
|
|
682
|
+
const content = __rspack_external_fs.readFileSync(absolutePath, 'utf-8');
|
|
683
|
+
return JSON.parse(content);
|
|
684
|
+
} catch (jsonErr) {
|
|
685
|
+
throw new Error(`Failed to load config file: ${configPath}\nError: ${error.message || error}`);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
async function loadCustomConfig(projectPath) {
|
|
690
|
+
const configPath = findConfigFile(projectPath);
|
|
691
|
+
if (configPath) {
|
|
692
|
+
if (await config_loader_isUsingExperimentalConfig(projectPath)) try {
|
|
693
|
+
const userConfig = await loadConfigFile(configPath);
|
|
694
|
+
if (userConfig && 'function' == typeof userConfig.config) return userConfig.config;
|
|
695
|
+
if (userConfig && userConfig.config && 'object' == typeof userConfig.config) {
|
|
696
|
+
const partial = userConfig.config;
|
|
697
|
+
return (config)=>{
|
|
698
|
+
const requireFn = createRequire(import.meta.url);
|
|
699
|
+
const { merge } = requireFn('webpack-merge');
|
|
700
|
+
return merge(config, partial);
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
} catch (err) {
|
|
704
|
+
const error = err;
|
|
705
|
+
console.error(configLoadingError(configPath, error));
|
|
706
|
+
throw err;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
return (config)=>config;
|
|
710
|
+
}
|
|
711
|
+
async function loadCommandConfig(projectPath, command) {
|
|
712
|
+
const configPath = findConfigFile(projectPath);
|
|
713
|
+
if (configPath) {
|
|
714
|
+
if (await config_loader_isUsingExperimentalConfig(projectPath)) try {
|
|
715
|
+
const userConfig = await loadConfigFile(configPath);
|
|
716
|
+
const baseExtensions = userConfig && userConfig.extensions ? {
|
|
717
|
+
extensions: userConfig.extensions
|
|
718
|
+
} : {};
|
|
719
|
+
const baseTranspilePackages = userConfig && Array.isArray(userConfig.transpilePackages) ? {
|
|
720
|
+
transpilePackages: userConfig.transpilePackages
|
|
721
|
+
} : {};
|
|
722
|
+
const perCommand = userConfig && userConfig.commands && userConfig.commands[command] ? userConfig.commands[command] : {};
|
|
723
|
+
return {
|
|
724
|
+
...baseExtensions,
|
|
725
|
+
...baseTranspilePackages,
|
|
726
|
+
...perCommand
|
|
727
|
+
};
|
|
728
|
+
} catch (err) {
|
|
729
|
+
const error = err;
|
|
730
|
+
console.error(configLoadingError(configPath, error));
|
|
731
|
+
throw err;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return {};
|
|
735
|
+
}
|
|
736
|
+
async function loadBrowserConfig(projectPath, browser = 'chrome') {
|
|
737
|
+
const configPath = findConfigFile(projectPath);
|
|
738
|
+
if (configPath) {
|
|
739
|
+
if (await config_loader_isUsingExperimentalConfig(projectPath)) try {
|
|
740
|
+
const userConfig = await loadConfigFile(configPath);
|
|
741
|
+
if (userConfig && userConfig.browser) {
|
|
742
|
+
const browsers = userConfig.browser;
|
|
743
|
+
if ('chromium-based' === browser) {
|
|
744
|
+
if (browsers['chromium-based']) return browsers['chromium-based'];
|
|
745
|
+
if (browsers.chromium) return browsers.chromium;
|
|
746
|
+
} else if ('gecko-based' === browser) {
|
|
747
|
+
if (browsers['gecko-based']) return browsers['gecko-based'];
|
|
748
|
+
if (browsers.firefox) return browsers.firefox;
|
|
749
|
+
} else {
|
|
750
|
+
const direct = browsers[browser];
|
|
751
|
+
if (direct) return direct;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
} catch (err) {
|
|
755
|
+
const error = err;
|
|
756
|
+
console.error(configLoadingError(configPath, error));
|
|
757
|
+
throw err;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
return {
|
|
761
|
+
browser: browser || 'chrome'
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
let userMessageDelivered = false;
|
|
765
|
+
async function config_loader_isUsingExperimentalConfig(projectPath) {
|
|
766
|
+
const configPath = findConfigFile(projectPath);
|
|
767
|
+
if (configPath) {
|
|
768
|
+
if (!userMessageDelivered) {
|
|
769
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(isUsingExperimentalConfig('extension.config.js'));
|
|
770
|
+
userMessageDelivered = true;
|
|
771
|
+
}
|
|
772
|
+
return true;
|
|
773
|
+
}
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
function assertNoManagedDependencyConflicts(userPackageJsonPath, projectPath) {
|
|
777
|
+
try {
|
|
778
|
+
const raw = __rspack_external_fs.readFileSync(userPackageJsonPath, 'utf-8');
|
|
779
|
+
const userPackageJson = JSON.parse(raw);
|
|
780
|
+
const userDeps = Array.from(new Set([
|
|
781
|
+
...Object.keys(userPackageJson.dependencies || {}),
|
|
782
|
+
...Object.keys(userPackageJson.devDependencies || {}),
|
|
783
|
+
...Object.keys(userPackageJson.optionalDependencies || {}),
|
|
784
|
+
...Object.keys(userPackageJson.peerDependencies || {})
|
|
785
|
+
]));
|
|
786
|
+
const managedDeps = new Set([
|
|
787
|
+
...Object.keys(package_namespaceObject.El || {}),
|
|
788
|
+
...Object.keys(package_namespaceObject.optionalDependencies || {})
|
|
789
|
+
]);
|
|
790
|
+
managedDeps.delete('webpack');
|
|
791
|
+
const userConfigJs = __rspack_external_path.join(projectPath, 'extension.config.js');
|
|
792
|
+
const userConfigMjs = __rspack_external_path.join(projectPath, 'extension.config.mjs');
|
|
793
|
+
const hasConfig = __rspack_external_fs.existsSync(userConfigJs) || __rspack_external_fs.existsSync(userConfigMjs);
|
|
794
|
+
if (!hasConfig) return;
|
|
795
|
+
const configPath = __rspack_external_fs.existsSync(userConfigJs) ? userConfigJs : userConfigMjs;
|
|
796
|
+
const configSource = __rspack_external_fs.readFileSync(configPath, 'utf-8');
|
|
797
|
+
const duplicates = userDeps.filter((d)=>managedDeps.has(d)).filter((d)=>configSource.includes(d)).sort();
|
|
798
|
+
if (duplicates.length > 0) {
|
|
799
|
+
console.error(managedDependencyConflict(duplicates, userPackageJsonPath));
|
|
800
|
+
process.exit(1);
|
|
801
|
+
}
|
|
802
|
+
} catch (error) {
|
|
803
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn(error);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
function asAbsolute(p) {
|
|
807
|
+
return __rspack_external_path.isAbsolute(p) ? p : __rspack_external_path.resolve(p);
|
|
808
|
+
}
|
|
809
|
+
function getDirs(struct) {
|
|
810
|
+
const manifestDir = asAbsolute(__rspack_external_path.dirname(struct.manifestPath));
|
|
811
|
+
const packageJsonDir = asAbsolute(struct.packageJsonPath ? __rspack_external_path.dirname(struct.packageJsonPath) : manifestDir);
|
|
812
|
+
return {
|
|
813
|
+
manifestDir,
|
|
814
|
+
packageJsonDir
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
function getNodeModulesDir(packageJsonDir) {
|
|
818
|
+
return asAbsolute(__rspack_external_path.join(packageJsonDir, 'node_modules'));
|
|
819
|
+
}
|
|
820
|
+
function needsInstall(packageJsonDir) {
|
|
821
|
+
const nm = getNodeModulesDir(packageJsonDir);
|
|
822
|
+
const packageJsonPath = __rspack_external_path.join(packageJsonDir, 'package.json');
|
|
823
|
+
if (!__rspack_external_fs.existsSync(packageJsonPath)) return false;
|
|
824
|
+
try {
|
|
825
|
+
const raw = __rspack_external_fs.readFileSync(packageJsonPath, 'utf-8');
|
|
826
|
+
const packageJson = JSON.parse(raw);
|
|
827
|
+
const depsCount = Object.keys(packageJson?.dependencies || {}).length;
|
|
828
|
+
const devDepsCount = Object.keys(packageJson?.devDependencies || {}).length;
|
|
829
|
+
if (depsCount + devDepsCount === 0) return false;
|
|
830
|
+
if (!__rspack_external_fs.existsSync(nm)) return true;
|
|
831
|
+
const deps = Object.keys(packageJson?.dependencies || {});
|
|
832
|
+
const devDeps = Object.keys(packageJson?.devDependencies || {});
|
|
833
|
+
if (__rspack_external_fs.existsSync(__rspack_external_path.join(nm, '.pnpm'))) return false;
|
|
834
|
+
if (__rspack_external_fs.existsSync(__rspack_external_path.join(nm, '.modules.yaml'))) return false;
|
|
835
|
+
const hasInstalledDep = [
|
|
836
|
+
...deps,
|
|
837
|
+
...devDeps
|
|
838
|
+
].some((dep)=>__rspack_external_fs.existsSync(__rspack_external_path.join(nm, dep)));
|
|
839
|
+
return !hasInstalledDep;
|
|
840
|
+
} catch {
|
|
841
|
+
return true;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
function normalizeBrowser(browser, chromiumBinary, geckoBinary) {
|
|
845
|
+
const requested = String(browser || '');
|
|
846
|
+
if (chromiumBinary) {
|
|
847
|
+
if (!requested || 'chromium-based' === requested) return 'chromium-based';
|
|
848
|
+
if ('chromium' === requested) return 'chromium';
|
|
849
|
+
if ('edge' === requested) return 'edge';
|
|
850
|
+
if ('chrome' === requested) return 'chrome';
|
|
851
|
+
}
|
|
852
|
+
if (geckoBinary) {
|
|
853
|
+
if (!requested || 'gecko-based' === requested || 'firefox-based' === requested) return 'gecko-based';
|
|
854
|
+
if ('firefox' === requested) return 'firefox';
|
|
855
|
+
}
|
|
856
|
+
switch(requested){
|
|
857
|
+
case 'chrome':
|
|
858
|
+
return 'chrome';
|
|
859
|
+
case 'edge':
|
|
860
|
+
return 'edge';
|
|
861
|
+
case 'chromium':
|
|
862
|
+
return 'chromium';
|
|
863
|
+
case 'chromium-based':
|
|
864
|
+
return 'chromium-based';
|
|
865
|
+
case 'firefox':
|
|
866
|
+
return 'firefox';
|
|
867
|
+
case 'gecko-based':
|
|
868
|
+
case 'firefox-based':
|
|
869
|
+
return 'gecko-based';
|
|
870
|
+
default:
|
|
871
|
+
return browser || 'chrome';
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
function getDistPath(packageJsonDir, browser) {
|
|
875
|
+
return asAbsolute(__rspack_external_path.join(packageJsonDir, 'dist', browser));
|
|
876
|
+
}
|
|
877
|
+
function computePreviewOutputPath(struct, browser, explicitOutputPath) {
|
|
878
|
+
const { manifestDir, packageJsonDir } = getDirs(struct);
|
|
879
|
+
if (explicitOutputPath) return asAbsolute(explicitOutputPath);
|
|
880
|
+
if (struct.packageJsonPath) {
|
|
881
|
+
const distDir = getDistPath(packageJsonDir, browser);
|
|
882
|
+
try {
|
|
883
|
+
if (__rspack_external_fs.existsSync(__rspack_external_path.join(distDir, 'manifest.json'))) return distDir;
|
|
884
|
+
} catch {}
|
|
885
|
+
}
|
|
886
|
+
return manifestDir;
|
|
887
|
+
}
|
|
888
|
+
function devtoolsEngineFor(browser) {
|
|
889
|
+
switch(browser){
|
|
890
|
+
case 'chrome':
|
|
891
|
+
return 'chrome';
|
|
892
|
+
case 'edge':
|
|
893
|
+
return 'edge';
|
|
894
|
+
case 'chromium':
|
|
895
|
+
case 'chromium-based':
|
|
896
|
+
return 'chromium';
|
|
897
|
+
case 'firefox':
|
|
898
|
+
case 'gecko-based':
|
|
899
|
+
return 'firefox';
|
|
900
|
+
default:
|
|
901
|
+
return 'chrome';
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
function isDir(p) {
|
|
905
|
+
try {
|
|
906
|
+
return __rspack_external_fs.existsSync(p) && __rspack_external_fs.statSync(p).isDirectory();
|
|
907
|
+
} catch {
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
function isFile(p) {
|
|
912
|
+
try {
|
|
913
|
+
return __rspack_external_fs.existsSync(p) && __rspack_external_fs.statSync(p).isFile();
|
|
914
|
+
} catch {
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
function toAbs(projectRoot, p) {
|
|
919
|
+
return __rspack_external_path.isAbsolute(p) ? p : __rspack_external_path.resolve(projectRoot, p);
|
|
920
|
+
}
|
|
921
|
+
function isValidExtensionRoot(dir) {
|
|
922
|
+
if (!isDir(dir)) return false;
|
|
923
|
+
return isFile(__rspack_external_path.join(dir, 'manifest.json'));
|
|
924
|
+
}
|
|
925
|
+
function normalizeCompanionConfig(config) {
|
|
926
|
+
const explicitPaths = [];
|
|
927
|
+
let scanDir;
|
|
928
|
+
if (Array.isArray(config)) explicitPaths.push(...config.filter((p)=>'string' == typeof p));
|
|
929
|
+
else if (config && 'object' == typeof config) {
|
|
930
|
+
if (Array.isArray(config.paths)) explicitPaths.push(...config.paths.filter((p)=>'string' == typeof p));
|
|
931
|
+
if ('string' == typeof config.dir && config.dir.trim().length > 0) scanDir = config.dir.trim();
|
|
932
|
+
}
|
|
933
|
+
return {
|
|
934
|
+
dir: scanDir,
|
|
935
|
+
paths: explicitPaths
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
function resolve_config_isPathLike(value) {
|
|
939
|
+
if (__rspack_external_path.isAbsolute(value)) return true;
|
|
940
|
+
if (value.startsWith('./') || value.startsWith('../')) return true;
|
|
941
|
+
return value.includes('/') || value.includes('\\');
|
|
942
|
+
}
|
|
943
|
+
function isSubpathOf(parent, child) {
|
|
944
|
+
const rel = __rspack_external_path.relative(parent, child);
|
|
945
|
+
return '' !== rel && !rel.startsWith('..') && !__rspack_external_path.isAbsolute(rel);
|
|
946
|
+
}
|
|
947
|
+
function getBrowserFolder(browser) {
|
|
948
|
+
if ('firefox' === browser || 'gecko-based' === browser || 'firefox-based' === browser) return 'firefox';
|
|
949
|
+
if ('edge' === browser) return 'edge';
|
|
950
|
+
return 'chrome';
|
|
951
|
+
}
|
|
952
|
+
function parseChromeWebStoreId(url) {
|
|
953
|
+
if ('chromewebstore.google.com' !== url.hostname) return null;
|
|
954
|
+
const match = url.pathname.match(/\/([a-z]{32})(?:\/|$)/i);
|
|
955
|
+
return match ? match[1] : null;
|
|
956
|
+
}
|
|
957
|
+
function parseEdgeAddonsId(url) {
|
|
958
|
+
if ('microsoftedge.microsoft.com' !== url.hostname) return null;
|
|
959
|
+
const match = url.pathname.match(/\/([a-z]{32})(?:\/|$)/i);
|
|
960
|
+
return match ? match[1] : null;
|
|
961
|
+
}
|
|
962
|
+
function parseAmoSlug(url) {
|
|
963
|
+
if ('addons.mozilla.org' !== url.hostname) return null;
|
|
964
|
+
const match = url.pathname.match(/\/addon\/([^/]+)(?:\/|$)/i);
|
|
965
|
+
return match ? match[1] : null;
|
|
966
|
+
}
|
|
967
|
+
function parseStoreUrl(raw) {
|
|
968
|
+
let url;
|
|
969
|
+
try {
|
|
970
|
+
url = new URL(raw);
|
|
971
|
+
} catch {
|
|
972
|
+
return null;
|
|
973
|
+
}
|
|
974
|
+
const chromeId = parseChromeWebStoreId(url);
|
|
975
|
+
if (chromeId) return {
|
|
976
|
+
browser: 'chrome',
|
|
977
|
+
id: chromeId
|
|
978
|
+
};
|
|
979
|
+
const edgeId = parseEdgeAddonsId(url);
|
|
980
|
+
if (edgeId) return {
|
|
981
|
+
browser: 'edge',
|
|
982
|
+
id: edgeId
|
|
983
|
+
};
|
|
984
|
+
const amoSlug = parseAmoSlug(url);
|
|
985
|
+
if (amoSlug) return {
|
|
986
|
+
browser: 'firefox',
|
|
987
|
+
id: amoSlug
|
|
988
|
+
};
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
function ensurePathsUnderExtensions(projectRoot, paths) {
|
|
992
|
+
const extensionsRoot = __rspack_external_path.resolve(projectRoot, 'extensions');
|
|
993
|
+
return paths.map((p)=>{
|
|
994
|
+
const abs = toAbs(projectRoot, p);
|
|
995
|
+
if (abs !== extensionsRoot && !isSubpathOf(extensionsRoot, abs) && __rspack_external_path.resolve(abs) !== extensionsRoot) throw new Error(`Companion extensions must be inside ${extensionsRoot}.\nInvalid path: ${abs}`);
|
|
996
|
+
return abs;
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
function findExtensionRoots(dir, maxDepth = 3) {
|
|
1000
|
+
const found = [];
|
|
1001
|
+
function walk(current, depth) {
|
|
1002
|
+
if (depth > maxDepth) return;
|
|
1003
|
+
if (!isDir(current)) return;
|
|
1004
|
+
if (isValidExtensionRoot(current)) return void found.push(current);
|
|
1005
|
+
let entries = [];
|
|
1006
|
+
try {
|
|
1007
|
+
entries = __rspack_external_fs.readdirSync(current, {
|
|
1008
|
+
withFileTypes: true
|
|
1009
|
+
});
|
|
1010
|
+
} catch {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
for (const ent of entries)if (ent.isDirectory()) {
|
|
1014
|
+
if (!ent.name.startsWith('.')) walk(__rspack_external_path.join(current, ent.name), depth + 1);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
walk(dir, 0);
|
|
1018
|
+
return found;
|
|
1019
|
+
}
|
|
1020
|
+
async function runExtensionFromStore(url, outDir) {
|
|
1021
|
+
const isAuthor = 'true' === process.env.EXTENSION_AUTHOR_MODE;
|
|
1022
|
+
await fetchExtensionFromStore(url, {
|
|
1023
|
+
outDir,
|
|
1024
|
+
extract: true,
|
|
1025
|
+
logger: isAuthor ? {
|
|
1026
|
+
onInfo: (message)=>console.log(message),
|
|
1027
|
+
onWarn: (message)=>console.warn(message),
|
|
1028
|
+
onError: (message, error)=>console.error(message, error)
|
|
1029
|
+
} : void 0
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
async function resolveStoreExtensionToPath(opts) {
|
|
1033
|
+
const { projectRoot, storeUrl, browser, id } = opts;
|
|
1034
|
+
const extensionsRoot = __rspack_external_path.resolve(projectRoot, 'extensions');
|
|
1035
|
+
const targetRoot = __rspack_external_path.join(extensionsRoot, browser, id);
|
|
1036
|
+
const manifestPath = __rspack_external_path.join(targetRoot, 'manifest.json');
|
|
1037
|
+
if (isFile(manifestPath)) return targetRoot;
|
|
1038
|
+
await runExtensionFromStore(storeUrl, __rspack_external_path.join(extensionsRoot, browser));
|
|
1039
|
+
const candidates = findExtensionRoots(__rspack_external_path.join(extensionsRoot, browser));
|
|
1040
|
+
let selected;
|
|
1041
|
+
if (1 === candidates.length) selected = candidates[0];
|
|
1042
|
+
else if (candidates.length > 1) {
|
|
1043
|
+
const directMatch = candidates.find((c)=>__rspack_external_path.basename(c) === id);
|
|
1044
|
+
const versionedMatch = candidates.find((c)=>__rspack_external_path.basename(c).startsWith(`${id}@`));
|
|
1045
|
+
if (directMatch) selected = directMatch;
|
|
1046
|
+
else if (versionedMatch) selected = versionedMatch;
|
|
1047
|
+
}
|
|
1048
|
+
if (!selected) throw new Error(`Could not locate an unpacked extension from ${storeUrl}.`);
|
|
1049
|
+
__rspack_external_fs.mkdirSync(__rspack_external_path.dirname(targetRoot), {
|
|
1050
|
+
recursive: true
|
|
1051
|
+
});
|
|
1052
|
+
if (__rspack_external_path.basename(selected).startsWith(`${id}@`)) __rspack_external_fs.renameSync(selected, targetRoot);
|
|
1053
|
+
return targetRoot;
|
|
1054
|
+
}
|
|
1055
|
+
async function resolveCompanionExtensionsConfig(opts) {
|
|
1056
|
+
const { projectRoot, browser, config } = opts;
|
|
1057
|
+
if (!config) return;
|
|
1058
|
+
const normalized = normalizeCompanionConfig(config);
|
|
1059
|
+
const runtimeBrowser = getBrowserFolder(browser);
|
|
1060
|
+
const resolvedPaths = [];
|
|
1061
|
+
const localPaths = [];
|
|
1062
|
+
for (const entry of normalized.paths){
|
|
1063
|
+
const parsedStore = parseStoreUrl(entry);
|
|
1064
|
+
if (parsedStore) {
|
|
1065
|
+
if (parsedStore.browser !== runtimeBrowser) continue;
|
|
1066
|
+
const resolvedPath = await resolveStoreExtensionToPath({
|
|
1067
|
+
projectRoot,
|
|
1068
|
+
storeUrl: entry,
|
|
1069
|
+
browser: parsedStore.browser,
|
|
1070
|
+
id: parsedStore.id
|
|
1071
|
+
});
|
|
1072
|
+
resolvedPaths.push(resolvedPath);
|
|
1073
|
+
continue;
|
|
1074
|
+
}
|
|
1075
|
+
if (resolve_config_isPathLike(entry)) localPaths.push(entry);
|
|
1076
|
+
}
|
|
1077
|
+
if (localPaths.length > 0) {
|
|
1078
|
+
const absLocalPaths = ensurePathsUnderExtensions(projectRoot, localPaths);
|
|
1079
|
+
resolvedPaths.push(...absLocalPaths);
|
|
1080
|
+
}
|
|
1081
|
+
const output = {};
|
|
1082
|
+
if ('string' == typeof normalized.dir) {
|
|
1083
|
+
const absDir = toAbs(projectRoot, normalized.dir);
|
|
1084
|
+
const extensionsRoot = __rspack_external_path.resolve(projectRoot, 'extensions');
|
|
1085
|
+
if (absDir !== extensionsRoot && !isSubpathOf(extensionsRoot, absDir)) throw new Error(`extensions.dir must be inside ${extensionsRoot}.\nInvalid dir: ${absDir}`);
|
|
1086
|
+
output.dir = normalized.dir;
|
|
1087
|
+
}
|
|
1088
|
+
if (resolvedPaths.length > 0) output.paths = resolvedPaths;
|
|
1089
|
+
return output;
|
|
1090
|
+
}
|
|
1091
|
+
function isUnderPublicDir(entry, projectRoot, publicDir) {
|
|
1092
|
+
if (!entry) return false;
|
|
1093
|
+
const normalizedEntry = String(entry);
|
|
1094
|
+
const candidate = path_0.isAbsolute(normalizedEntry) ? normalizedEntry : path_0.join(projectRoot, normalizedEntry);
|
|
1095
|
+
const rel = path_0.relative(publicDir, candidate);
|
|
1096
|
+
return Boolean(rel && !rel.startsWith('..') && !path_0.isAbsolute(rel));
|
|
1097
|
+
}
|
|
1098
|
+
function filterPublicEntrypoints(list, projectRoot, publicDir) {
|
|
1099
|
+
const next = {};
|
|
1100
|
+
for (const [key, value] of Object.entries(list || {})){
|
|
1101
|
+
if (Array.isArray(value)) {
|
|
1102
|
+
const filtered = value.filter((entry)=>!isUnderPublicDir(String(entry), projectRoot, publicDir));
|
|
1103
|
+
if (filtered.length > 0) next[key] = filtered;
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
if ('string' == typeof value) {
|
|
1107
|
+
if (!isUnderPublicDir(value, projectRoot, publicDir)) next[key] = value;
|
|
1108
|
+
continue;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
return next;
|
|
1112
|
+
}
|
|
1113
|
+
function getSpecialFoldersDataForCompiler(compiler) {
|
|
1114
|
+
const projectRoot = compiler.options.context || '';
|
|
1115
|
+
const publicDir = path_0.join(projectRoot, 'public');
|
|
1116
|
+
const data = getSpecialFoldersData({
|
|
1117
|
+
manifestPath: path_0.join(projectRoot, 'package.json')
|
|
1118
|
+
});
|
|
1119
|
+
return finalizeSpecialFoldersData(data, projectRoot, publicDir);
|
|
1120
|
+
}
|
|
1121
|
+
function getSpecialFoldersDataForProjectRoot(projectRoot) {
|
|
1122
|
+
const publicDir = path_0.join(projectRoot, 'public');
|
|
1123
|
+
const data = getSpecialFoldersData({
|
|
1124
|
+
manifestPath: path_0.join(projectRoot, 'package.json')
|
|
1125
|
+
});
|
|
1126
|
+
return finalizeSpecialFoldersData(data, projectRoot, publicDir);
|
|
1127
|
+
}
|
|
1128
|
+
function finalizeSpecialFoldersData(data, projectRoot, publicDir) {
|
|
1129
|
+
return {
|
|
1130
|
+
...data,
|
|
1131
|
+
pages: filterPublicEntrypoints(data.pages, projectRoot, publicDir),
|
|
1132
|
+
scripts: filterPublicEntrypoints(data.scripts, projectRoot, publicDir),
|
|
1133
|
+
extensions: {
|
|
1134
|
+
dir: './extensions'
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
function sanitize(obj) {
|
|
1139
|
+
return Object.fromEntries(Object.entries(obj || {}).filter(([, value])=>void 0 !== value));
|
|
1140
|
+
}
|
|
1141
|
+
function nowISO() {
|
|
1142
|
+
return new Date().toISOString();
|
|
1143
|
+
}
|
|
1144
|
+
function createRunId() {
|
|
1145
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1146
|
+
}
|
|
1147
|
+
function plugin_playwright_ensureDirSync(dirPath) {
|
|
1148
|
+
try {
|
|
1149
|
+
__rspack_external_fs.mkdirSync(dirPath, {
|
|
1150
|
+
recursive: true
|
|
1151
|
+
});
|
|
1152
|
+
} catch {}
|
|
1153
|
+
}
|
|
1154
|
+
function writeJsonAtomic(filePath, value) {
|
|
1155
|
+
try {
|
|
1156
|
+
const tmpPath = `${filePath}.tmp-${process.pid}`;
|
|
1157
|
+
__rspack_external_fs.writeFileSync(tmpPath, JSON.stringify(value, null, 2) + '\n', 'utf-8');
|
|
1158
|
+
__rspack_external_fs.renameSync(tmpPath, filePath);
|
|
1159
|
+
} catch {}
|
|
1160
|
+
}
|
|
1161
|
+
function getPlaywrightMetadataDir(packageJsonDir, browser) {
|
|
1162
|
+
return asAbsolute(__rspack_external_path.join(packageJsonDir, 'dist', 'extension-js', browser));
|
|
1163
|
+
}
|
|
1164
|
+
function createPlaywrightMetadataWriter(options) {
|
|
1165
|
+
const metadataDir = getPlaywrightMetadataDir(options.packageJsonDir, options.browser);
|
|
1166
|
+
const readyPath = asAbsolute(__rspack_external_path.join(metadataDir, 'ready.json'));
|
|
1167
|
+
const eventsPath = asAbsolute(__rspack_external_path.join(metadataDir, 'events.ndjson'));
|
|
1168
|
+
const base = {
|
|
1169
|
+
command: options.command,
|
|
1170
|
+
browser: options.browser,
|
|
1171
|
+
runId: createRunId(),
|
|
1172
|
+
startedAt: nowISO(),
|
|
1173
|
+
distPath: options.distPath,
|
|
1174
|
+
manifestPath: options.manifestPath,
|
|
1175
|
+
port: (()=>{
|
|
1176
|
+
if ('number' == typeof options.port && Number.isFinite(options.port)) return options.port;
|
|
1177
|
+
if ('string' == typeof options.port) {
|
|
1178
|
+
const parsed = parseInt(options.port, 10);
|
|
1179
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
1180
|
+
}
|
|
1181
|
+
return null;
|
|
1182
|
+
})()
|
|
1183
|
+
};
|
|
1184
|
+
function writeReady(status, extra) {
|
|
1185
|
+
plugin_playwright_ensureDirSync(metadataDir);
|
|
1186
|
+
const payload = {
|
|
1187
|
+
...base,
|
|
1188
|
+
status,
|
|
1189
|
+
pid: process.pid,
|
|
1190
|
+
ts: nowISO(),
|
|
1191
|
+
compiledAt: extra?.compiledAt ?? null,
|
|
1192
|
+
errors: Array.isArray(extra?.errors) ? extra.errors : []
|
|
1193
|
+
};
|
|
1194
|
+
if (extra?.code) payload.code = extra.code;
|
|
1195
|
+
if (extra?.message) payload.message = extra.message;
|
|
1196
|
+
writeJsonAtomic(readyPath, payload);
|
|
1197
|
+
}
|
|
1198
|
+
function appendEvent(event) {
|
|
1199
|
+
plugin_playwright_ensureDirSync(metadataDir);
|
|
1200
|
+
try {
|
|
1201
|
+
__rspack_external_fs.appendFileSync(eventsPath, `${JSON.stringify(event)}\n`, 'utf-8');
|
|
1202
|
+
} catch {}
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
metadataDir,
|
|
1206
|
+
readyPath,
|
|
1207
|
+
eventsPath,
|
|
1208
|
+
writeStarting () {
|
|
1209
|
+
writeReady('starting');
|
|
1210
|
+
},
|
|
1211
|
+
writeReady (compiledAt) {
|
|
1212
|
+
writeReady('ready', {
|
|
1213
|
+
compiledAt: compiledAt || nowISO()
|
|
1214
|
+
});
|
|
1215
|
+
},
|
|
1216
|
+
writeError (code, message, errors) {
|
|
1217
|
+
writeReady('error', {
|
|
1218
|
+
code,
|
|
1219
|
+
message,
|
|
1220
|
+
errors: Array.isArray(errors) ? errors : [],
|
|
1221
|
+
compiledAt: null
|
|
1222
|
+
});
|
|
1223
|
+
},
|
|
1224
|
+
appendEvent
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
class PlaywrightPlugin {
|
|
1228
|
+
static name = 'plugin-playwright';
|
|
1229
|
+
writer;
|
|
1230
|
+
command;
|
|
1231
|
+
browser;
|
|
1232
|
+
constructor(options){
|
|
1233
|
+
this.browser = String(options.browser || 'chromium');
|
|
1234
|
+
this.command = options.command || ('development' === options.mode ? 'dev' : 'start');
|
|
1235
|
+
this.writer = createPlaywrightMetadataWriter({
|
|
1236
|
+
packageJsonDir: options.packageJsonDir,
|
|
1237
|
+
browser: this.browser,
|
|
1238
|
+
command: this.command,
|
|
1239
|
+
distPath: options.outputPath,
|
|
1240
|
+
manifestPath: options.manifestPath,
|
|
1241
|
+
port: options.port
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
apply(compiler) {
|
|
1245
|
+
this.writer.writeStarting();
|
|
1246
|
+
compiler.hooks.compile.tap(PlaywrightPlugin.name, ()=>{
|
|
1247
|
+
this.writer.appendEvent({
|
|
1248
|
+
type: 'compile_start',
|
|
1249
|
+
ts: nowISO(),
|
|
1250
|
+
command: this.command,
|
|
1251
|
+
browser: this.browser
|
|
1252
|
+
});
|
|
1253
|
+
});
|
|
1254
|
+
compiler.hooks.done.tap(PlaywrightPlugin.name, (stats)=>{
|
|
1255
|
+
const durationMs = Number((stats?.compilation?.endTime || 0) - (stats?.compilation?.startTime || 0));
|
|
1256
|
+
const hasErrors = Boolean(stats?.hasErrors?.());
|
|
1257
|
+
const errorsCount = Number(Array.isArray(stats?.toJson?.({
|
|
1258
|
+
all: false,
|
|
1259
|
+
errors: true
|
|
1260
|
+
})?.errors) ? stats.toJson({
|
|
1261
|
+
all: false,
|
|
1262
|
+
errors: true
|
|
1263
|
+
}).errors.length : 0);
|
|
1264
|
+
if (hasErrors) {
|
|
1265
|
+
this.writer.appendEvent({
|
|
1266
|
+
type: 'compile_error',
|
|
1267
|
+
ts: nowISO(),
|
|
1268
|
+
command: this.command,
|
|
1269
|
+
browser: this.browser,
|
|
1270
|
+
durationMs: Number.isFinite(durationMs) ? durationMs : void 0,
|
|
1271
|
+
errorCount: Number.isFinite(errorsCount) ? errorsCount : 1
|
|
1272
|
+
});
|
|
1273
|
+
this.writer.writeError('compile_error', 'Compilation failed', [
|
|
1274
|
+
`errors: ${String(errorsCount || 1)}`
|
|
1275
|
+
]);
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
this.writer.appendEvent({
|
|
1279
|
+
type: 'compile_success',
|
|
1280
|
+
ts: nowISO(),
|
|
1281
|
+
command: this.command,
|
|
1282
|
+
browser: this.browser,
|
|
1283
|
+
durationMs: Number.isFinite(durationMs) ? durationMs : void 0,
|
|
1284
|
+
errorCount: 0
|
|
1285
|
+
});
|
|
1286
|
+
this.writer.writeReady(nowISO());
|
|
1287
|
+
});
|
|
1288
|
+
compiler.hooks.failed.tap(PlaywrightPlugin.name, (error)=>{
|
|
1289
|
+
this.writer.appendEvent({
|
|
1290
|
+
type: 'compile_error',
|
|
1291
|
+
ts: nowISO(),
|
|
1292
|
+
command: this.command,
|
|
1293
|
+
browser: this.browser,
|
|
1294
|
+
errorCount: 1
|
|
1295
|
+
});
|
|
1296
|
+
this.writer.writeError('compile_failed', error instanceof Error ? error.message : String(error));
|
|
1297
|
+
});
|
|
1298
|
+
compiler.hooks.watchClose.tap(PlaywrightPlugin.name, ()=>{
|
|
1299
|
+
this.writer.appendEvent({
|
|
1300
|
+
type: 'shutdown',
|
|
1301
|
+
ts: nowISO(),
|
|
1302
|
+
command: this.command,
|
|
1303
|
+
browser: this.browser
|
|
1304
|
+
});
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
function resolveCompanionExtensionDirs(opts) {
|
|
1309
|
+
const { projectRoot, config } = opts;
|
|
1310
|
+
const normalized = normalizeCompanionConfig(config);
|
|
1311
|
+
const explicitPaths = normalized.paths;
|
|
1312
|
+
const scanDir = normalized.dir;
|
|
1313
|
+
const found = [];
|
|
1314
|
+
for (const p of explicitPaths){
|
|
1315
|
+
const abs = toAbs(projectRoot, p);
|
|
1316
|
+
if (isValidExtensionRoot(abs)) found.push(abs);
|
|
1317
|
+
}
|
|
1318
|
+
if (scanDir) {
|
|
1319
|
+
const absScan = toAbs(projectRoot, scanDir);
|
|
1320
|
+
if (isDir(absScan)) {
|
|
1321
|
+
let entries = [];
|
|
1322
|
+
try {
|
|
1323
|
+
entries = __rspack_external_fs.readdirSync(absScan, {
|
|
1324
|
+
withFileTypes: true
|
|
1325
|
+
});
|
|
1326
|
+
} catch {
|
|
1327
|
+
entries = [];
|
|
1328
|
+
}
|
|
1329
|
+
const scanOneLevel = (rootDir)=>{
|
|
1330
|
+
let dirEntries = [];
|
|
1331
|
+
try {
|
|
1332
|
+
dirEntries = __rspack_external_fs.readdirSync(rootDir, {
|
|
1333
|
+
withFileTypes: true
|
|
1334
|
+
});
|
|
1335
|
+
} catch {
|
|
1336
|
+
dirEntries = [];
|
|
1337
|
+
}
|
|
1338
|
+
for (const ent of dirEntries){
|
|
1339
|
+
if (!ent.isDirectory()) continue;
|
|
1340
|
+
if (ent.name.startsWith('.')) continue;
|
|
1341
|
+
const candidate = __rspack_external_path.join(rootDir, ent.name);
|
|
1342
|
+
if (isValidExtensionRoot(candidate)) found.push(candidate);
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
scanOneLevel(absScan);
|
|
1346
|
+
if ('extensions' === __rspack_external_path.basename(absScan)) for (const ent of entries){
|
|
1347
|
+
if (!ent.isDirectory()) continue;
|
|
1348
|
+
if (ent.name.startsWith('.')) continue;
|
|
1349
|
+
const browserDir = __rspack_external_path.join(absScan, ent.name);
|
|
1350
|
+
scanOneLevel(browserDir);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
const unique = [];
|
|
1355
|
+
const seen = new Set();
|
|
1356
|
+
for (const p of found)if (!seen.has(p)) {
|
|
1357
|
+
seen.add(p);
|
|
1358
|
+
unique.push(p);
|
|
1359
|
+
}
|
|
1360
|
+
return unique;
|
|
1361
|
+
}
|
|
1362
|
+
function hasNewTabOverride(extensionDir) {
|
|
1363
|
+
const manifestPath = __rspack_external_path.join(extensionDir, 'manifest.json');
|
|
1364
|
+
if (!__rspack_external_fs.existsSync(manifestPath)) return false;
|
|
1365
|
+
try {
|
|
1366
|
+
const raw = __rspack_external_fs.readFileSync(manifestPath, 'utf-8');
|
|
1367
|
+
const manifest = JSON.parse(raw);
|
|
1368
|
+
const newtab = manifest?.chrome_url_overrides?.newtab;
|
|
1369
|
+
return 'string' == typeof newtab && newtab.trim().length > 0;
|
|
1370
|
+
} catch {
|
|
1371
|
+
return false;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
function resolveBuiltInExtensionForBrowser(input) {
|
|
1375
|
+
const engine = devtoolsEngineFor(input.browser);
|
|
1376
|
+
const packageRelativeCandidates = [
|
|
1377
|
+
__rspack_external_path.join('dist', input.packageName, engine)
|
|
1378
|
+
];
|
|
1379
|
+
const normalizedBaseDir = __rspack_external_path.normalize(input.baseDir);
|
|
1380
|
+
const parentName = __rspack_external_path.basename(__rspack_external_path.dirname(normalizedBaseDir));
|
|
1381
|
+
const baseName = __rspack_external_path.basename(normalizedBaseDir);
|
|
1382
|
+
if ('programs' === parentName && 'develop' === baseName) packageRelativeCandidates.push(__rspack_external_path.join('..', '..', 'extensions', input.packageName, 'dist', engine));
|
|
1383
|
+
for (const rel of packageRelativeCandidates){
|
|
1384
|
+
const candidate = __rspack_external_path.resolve(input.baseDir, rel);
|
|
1385
|
+
if (__rspack_external_fs.existsSync(candidate)) return candidate;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
const RESERVED_BUILT_IN_NAMES = new Set([
|
|
1389
|
+
'extension-js-devtools',
|
|
1390
|
+
'extension-js-theme'
|
|
1391
|
+
]);
|
|
1392
|
+
function isReservedBuiltInPath(extensionPath) {
|
|
1393
|
+
const base = __rspack_external_path.basename(__rspack_external_path.normalize(extensionPath));
|
|
1394
|
+
if (RESERVED_BUILT_IN_NAMES.has(base)) return true;
|
|
1395
|
+
const segments = __rspack_external_path.normalize(extensionPath).split(__rspack_external_path.sep);
|
|
1396
|
+
return segments.some((segment)=>RESERVED_BUILT_IN_NAMES.has(segment));
|
|
1397
|
+
}
|
|
1398
|
+
function dedupeByResolvedPath(paths) {
|
|
1399
|
+
const seen = new Set();
|
|
1400
|
+
const result = [];
|
|
1401
|
+
for (const entry of paths){
|
|
1402
|
+
const resolved = __rspack_external_path.resolve(entry);
|
|
1403
|
+
if (!seen.has(resolved)) {
|
|
1404
|
+
seen.add(resolved);
|
|
1405
|
+
result.push(entry);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
return result;
|
|
1409
|
+
}
|
|
1410
|
+
function computeExtensionsToLoad(baseDir, mode, browser, userExtensionOutputPath, extraExtensionDirs = [], userManifestPath) {
|
|
1411
|
+
const list = [];
|
|
1412
|
+
try {
|
|
1413
|
+
const devtoolsForBrowser = resolveBuiltInExtensionForBrowser({
|
|
1414
|
+
baseDir,
|
|
1415
|
+
packageName: 'extension-js-devtools',
|
|
1416
|
+
browser
|
|
1417
|
+
});
|
|
1418
|
+
const themeForBrowser = resolveBuiltInExtensionForBrowser({
|
|
1419
|
+
baseDir,
|
|
1420
|
+
packageName: 'extension-js-theme',
|
|
1421
|
+
browser
|
|
1422
|
+
});
|
|
1423
|
+
const userHasNewTabOverride = hasNewTabOverride(userExtensionOutputPath) || ('string' == typeof userManifestPath ? hasNewTabOverride(__rspack_external_path.dirname(userManifestPath)) : false);
|
|
1424
|
+
const devtoolsHasNewTabOverride = devtoolsForBrowser ? hasNewTabOverride(devtoolsForBrowser) : false;
|
|
1425
|
+
const shouldSkipDevtoolsForNtpConflict = userHasNewTabOverride && devtoolsHasNewTabOverride;
|
|
1426
|
+
if (devtoolsForBrowser && !shouldSkipDevtoolsForNtpConflict) list.push(devtoolsForBrowser);
|
|
1427
|
+
if (themeForBrowser) list.push(themeForBrowser);
|
|
1428
|
+
} catch {}
|
|
1429
|
+
for (const p of extraExtensionDirs)if (!isReservedBuiltInPath(p)) list.push(p);
|
|
1430
|
+
list.push(userExtensionOutputPath);
|
|
1431
|
+
return dedupeByResolvedPath(list);
|
|
1432
|
+
}
|
|
1433
|
+
function getDarkModeDefaults(browser) {
|
|
1434
|
+
if ('chrome' === browser || 'edge' === browser || 'chromium' === browser || 'chromium-based' === browser) return {
|
|
1435
|
+
browserFlags: [
|
|
1436
|
+
'--force-dark-mode',
|
|
1437
|
+
'--enable-features=WebUIDarkMode'
|
|
1438
|
+
],
|
|
1439
|
+
preferences: {}
|
|
1440
|
+
};
|
|
1441
|
+
if ('firefox' === browser || 'gecko-based' === browser || 'firefox-based' === browser) return {
|
|
1442
|
+
browserFlags: [],
|
|
1443
|
+
preferences: {
|
|
1444
|
+
'ui.systemUsesDarkTheme': 1,
|
|
1445
|
+
'layout.css.prefers-color-scheme.content-override': 2,
|
|
1446
|
+
'devtools.theme': 'dark'
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
return {
|
|
1450
|
+
browserFlags: [],
|
|
1451
|
+
preferences: {}
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
function withDarkMode(config) {
|
|
1455
|
+
const defaults = getDarkModeDefaults(config.browser);
|
|
1456
|
+
const existingFlags = Array.isArray(config.browserFlags) ? [
|
|
1457
|
+
...config.browserFlags
|
|
1458
|
+
] : [];
|
|
1459
|
+
const nextFlags = [
|
|
1460
|
+
...existingFlags
|
|
1461
|
+
];
|
|
1462
|
+
for (const flag of defaults.browserFlags || [])if (!nextFlags.some((f)=>String(f).trim() === flag)) nextFlags.push(flag);
|
|
1463
|
+
const nextPreferences = {
|
|
1464
|
+
...config.preferences || {},
|
|
1465
|
+
...Object.fromEntries(Object.entries(defaults.preferences || {}).filter(([k])=>!(k in (config.preferences || {}))))
|
|
1466
|
+
};
|
|
1467
|
+
return {
|
|
1468
|
+
...config,
|
|
1469
|
+
browserFlags: nextFlags,
|
|
1470
|
+
preferences: nextPreferences
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
const cjsRequire = createRequire(import.meta.url);
|
|
1474
|
+
function messages_getLoggingPrefix(type) {
|
|
1475
|
+
const isAuthor = 'true' === process.env.EXTENSION_AUTHOR_MODE;
|
|
1476
|
+
if (isAuthor) {
|
|
1477
|
+
const base = 'error' === type ? 'ERROR Author says' : '⏵⏵⏵ Author says';
|
|
1478
|
+
return pintor.brightMagenta(base);
|
|
1479
|
+
}
|
|
1480
|
+
if ('error' === type) return pintor.red('ERROR');
|
|
1481
|
+
if ('warn' === type) return pintor.brightYellow('⏵⏵⏵');
|
|
1482
|
+
if ('info' === type) return pintor.gray('⏵⏵⏵');
|
|
1483
|
+
return pintor.green('⏵⏵⏵');
|
|
1484
|
+
}
|
|
1485
|
+
function messages_ready(mode, browser) {
|
|
1486
|
+
const key = String(browser || '').toLowerCase();
|
|
1487
|
+
const extensionOutput = 'firefox' === key || 'gecko-based' === key || 'firefox-based' === key || 'edge' === key ? 'Add-on' : 'Extension';
|
|
1488
|
+
const cap = 'firefox' === key || 'gecko-based' === key || 'firefox-based' === key ? 'Firefox' : String(browser || '').charAt(0).toUpperCase() + String(browser || '').slice(1);
|
|
1489
|
+
const pretty = pintor.green('ready for ' + mode);
|
|
1490
|
+
return `${messages_getLoggingPrefix('info')} ${cap} ${extensionOutput} ${pretty}.`;
|
|
1491
|
+
}
|
|
1492
|
+
function readJsonRecord(filePath) {
|
|
1493
|
+
try {
|
|
1494
|
+
return JSON.parse(__rspack_external_fs.readFileSync(filePath, 'utf8'));
|
|
1495
|
+
} catch {
|
|
1496
|
+
return null;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
function capitalizeToken(value) {
|
|
1500
|
+
return value.split('-').filter(Boolean).map((token)=>token.charAt(0).toUpperCase() + token.slice(1)).join('-');
|
|
1501
|
+
}
|
|
1502
|
+
function getExtensionVersion() {
|
|
1503
|
+
return process.env.EXTENSION_DEVELOP_VERSION || process.env.EXTENSION_CLI_VERSION || (()=>{
|
|
1504
|
+
try {
|
|
1505
|
+
return cjsRequire('../package.json').version;
|
|
1506
|
+
} catch {
|
|
1507
|
+
return 'unknown';
|
|
1508
|
+
}
|
|
1509
|
+
})();
|
|
1510
|
+
}
|
|
1511
|
+
function browserRunnerDisabled(args) {
|
|
1512
|
+
const manifest = readJsonRecord(args.manifestPath);
|
|
1513
|
+
const ready = readJsonRecord(args.readyPath);
|
|
1514
|
+
const browserLabel = capitalizeToken(String(args.browser || 'unknown'));
|
|
1515
|
+
const runId = String(ready?.runId || '').trim();
|
|
1516
|
+
const pid = Number.isInteger(ready?.pid) ? String(ready?.pid) : '';
|
|
1517
|
+
const runLabel = runId ? `${pintor.gray(runId)}${pid ? ` · ${pintor.gray(`PID ${pid}`)}` : ''}` : pid ? pintor.gray(`PID ${pid}`) : pintor.gray('n/a');
|
|
1518
|
+
const extensionName = String(manifest?.name || 'Extension');
|
|
1519
|
+
const extensionVersion = String(manifest?.version || '').trim();
|
|
1520
|
+
const extensionLabel = extensionVersion ? `${extensionName} ${extensionVersion}` : extensionName;
|
|
1521
|
+
const extensionJsVersion = getExtensionVersion();
|
|
1522
|
+
return [
|
|
1523
|
+
` 🧩 ${pintor.brightBlue('Extension.js')} ${pintor.gray(extensionJsVersion)}`,
|
|
1524
|
+
` Browser ${pintor.gray(args.browserModeLabel || `${browserLabel} (build-only mode)`)}`,
|
|
1525
|
+
` Extension ${pintor.gray(extensionLabel)}`,
|
|
1526
|
+
` Run ID ${runLabel}`
|
|
1527
|
+
].join('\n');
|
|
1528
|
+
}
|
|
1529
|
+
function portInUse(requestedPort, newPort) {
|
|
1530
|
+
return `Port: Requested port ${pintor.brightBlue(requestedPort.toString())} is in use; using ${pintor.brightBlue(newPort.toString())} instead.`;
|
|
1531
|
+
}
|
|
1532
|
+
function extensionJsRunnerError(error) {
|
|
1533
|
+
return `Extension.js Runner Error:\n${pintor.red(String(error))}`;
|
|
1534
|
+
}
|
|
1535
|
+
function autoExitModeEnabled(ms) {
|
|
1536
|
+
return `Auto-exit enabled. Will exit after ${pintor.brightBlue(ms.toString())} ms if idle.`;
|
|
1537
|
+
}
|
|
1538
|
+
function autoExitTriggered(ms) {
|
|
1539
|
+
return `Auto-exit triggered after ${pintor.brightBlue(ms.toString())} ms. Cleaning up...`;
|
|
1540
|
+
}
|
|
1541
|
+
function autoExitForceKill(ms) {
|
|
1542
|
+
return `Force-killing process after ${pintor.brightBlue(ms.toString())} ms to ensure exit.`;
|
|
1543
|
+
}
|
|
1544
|
+
function devServerStartTimeout(ms) {
|
|
1545
|
+
return [
|
|
1546
|
+
`Dev server startup is taking longer than expected (${pintor.brightBlue(ms.toString())} ms).`,
|
|
1547
|
+
"The bundler may have encountered an error before emitting the first build.",
|
|
1548
|
+
`If nothing else prints, try setting ${pintor.brightBlue('EXTENSION_VERBOSE=1')} for more logs.`
|
|
1549
|
+
].join('\n');
|
|
1550
|
+
}
|
|
1551
|
+
function bundlerFatalError(error) {
|
|
1552
|
+
const text = error instanceof Error ? error.stack || error.message : String(error);
|
|
1553
|
+
return `Build failed to start:\n${pintor.red(text)}`;
|
|
1554
|
+
}
|
|
1555
|
+
function bundlerRecompiling() {
|
|
1556
|
+
return "Recompiling due to file changes…";
|
|
1557
|
+
}
|
|
1558
|
+
function noEntrypointsDetected(port) {
|
|
1559
|
+
return [
|
|
1560
|
+
"No entrypoints or assets were produced by the initial compilation.",
|
|
1561
|
+
`The dev server is running on 127.0.0.1:${pintor.brightBlue(port.toString())}, but nothing is being built.`,
|
|
1562
|
+
"Possible causes:",
|
|
1563
|
+
" • Empty or missing entry configuration.",
|
|
1564
|
+
" • Extension-related plugins are disabled (entries not derived from manifest).",
|
|
1565
|
+
" • All sources are ignored or excluded.",
|
|
1566
|
+
`Try enabling verbose logs with ${pintor.brightBlue('EXTENSION_VERBOSE=1')} or review your extension config.`
|
|
1567
|
+
].join('\n');
|
|
1568
|
+
}
|
|
1569
|
+
function spacerLine() {
|
|
1570
|
+
return ' ';
|
|
1571
|
+
}
|
|
1572
|
+
var command_preview_dirname = __rspack_dirname(__rspack_fileURLToPath(import.meta.url));
|
|
1573
|
+
async function extensionPreview(pathOrRemoteUrl, previewOptions, browserLauncher) {
|
|
1574
|
+
const projectStructure = await getProjectStructure(pathOrRemoteUrl);
|
|
1575
|
+
const debug = 'true' === process.env.EXTENSION_AUTHOR_MODE;
|
|
1576
|
+
const { manifestDir, packageJsonDir } = getDirs(projectStructure);
|
|
1577
|
+
if (projectStructure.packageJsonPath) assertNoManagedDependencyConflicts(projectStructure.packageJsonPath, packageJsonDir);
|
|
1578
|
+
const browser = normalizeBrowser(previewOptions.browser || 'chrome', previewOptions.chromiumBinary, previewOptions.geckoBinary || previewOptions.firefoxBinary);
|
|
1579
|
+
const outputPath = computePreviewOutputPath(projectStructure, browser, previewOptions.outputPath);
|
|
1580
|
+
const distPath = getDistPath(packageJsonDir, browser);
|
|
1581
|
+
const metadataCommand = 'start' === previewOptions.metadataCommand ? 'start' : 'preview';
|
|
1582
|
+
const metadata = createPlaywrightMetadataWriter({
|
|
1583
|
+
packageJsonDir,
|
|
1584
|
+
browser: String(browser),
|
|
1585
|
+
command: metadataCommand,
|
|
1586
|
+
distPath,
|
|
1587
|
+
manifestPath: projectStructure.manifestPath,
|
|
1588
|
+
port: 'number' == typeof previewOptions.port ? previewOptions.port : 'string' == typeof previewOptions.port ? parseInt(previewOptions.port, 10) : null
|
|
1589
|
+
});
|
|
1590
|
+
metadata.writeStarting();
|
|
1591
|
+
if (debug) {
|
|
1592
|
+
console.log(debugDirs(manifestDir, packageJsonDir));
|
|
1593
|
+
console.log(debugBrowser(browser, previewOptions.chromiumBinary, previewOptions.geckoBinary || previewOptions.firefoxBinary));
|
|
1594
|
+
console.log(debugPreviewOutput(outputPath, distPath));
|
|
1595
|
+
}
|
|
1596
|
+
const manifestAtOutput = __rspack_external_path.join(outputPath, 'manifest.json');
|
|
1597
|
+
if (!__rspack_external_fs.existsSync(manifestAtOutput)) {
|
|
1598
|
+
metadata.writeError('preview_manifest_missing', `Expected manifest at ${manifestAtOutput}`);
|
|
1599
|
+
throw new Error(`Preview is run-only and does not compile.\nExpected an unpacked extension at:\n ${manifestAtOutput}\n\nRun \`extension build\` or \`extension dev\` first, or pass --output-path to an existing unpacked extension directory.`);
|
|
1600
|
+
}
|
|
1601
|
+
const commandConfig = await loadCommandConfig(packageJsonDir, metadataCommand);
|
|
1602
|
+
const browserConfig = await loadBrowserConfig(packageJsonDir, browser);
|
|
1603
|
+
console.log(previewing(browser));
|
|
1604
|
+
if (previewOptions.noBrowser) {
|
|
1605
|
+
console.log(previewSkippedNoBrowser(browser));
|
|
1606
|
+
metadata.writeReady();
|
|
1607
|
+
console.log(spacerLine());
|
|
1608
|
+
const browserLabel = String(browser || 'unknown');
|
|
1609
|
+
console.log(browserRunnerDisabled({
|
|
1610
|
+
browser: browserLabel,
|
|
1611
|
+
manifestPath: projectStructure.manifestPath,
|
|
1612
|
+
readyPath: metadata.readyPath,
|
|
1613
|
+
browserModeLabel: `${browserLabel.charAt(0).toUpperCase() + browserLabel.slice(1)} (no-browser mode)`
|
|
1614
|
+
}));
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
const safeBrowserConfig = sanitize(browserConfig);
|
|
1618
|
+
const safeCommandConfig = sanitize(commandConfig);
|
|
1619
|
+
const safePreviewOptions = sanitize(previewOptions);
|
|
1620
|
+
const specialFoldersData = getSpecialFoldersDataForProjectRoot(packageJsonDir);
|
|
1621
|
+
const mergedExtensionsConfig = safePreviewOptions.extensions ?? safeCommandConfig.extensions ?? safeBrowserConfig.extensions ?? specialFoldersData.extensions;
|
|
1622
|
+
const resolvedExtensionsConfig = await resolveCompanionExtensionsConfig({
|
|
1623
|
+
projectRoot: packageJsonDir,
|
|
1624
|
+
browser,
|
|
1625
|
+
config: mergedExtensionsConfig
|
|
1626
|
+
});
|
|
1627
|
+
const mergedGeckoBinary = safePreviewOptions.geckoBinary || safePreviewOptions.firefoxBinary || safeCommandConfig.geckoBinary || safeCommandConfig.firefoxBinary || safeBrowserConfig.geckoBinary || safeBrowserConfig.firefoxBinary;
|
|
1628
|
+
const mergedChromiumBinary = safePreviewOptions.chromiumBinary || safeCommandConfig.chromiumBinary || safeBrowserConfig.chromiumBinary;
|
|
1629
|
+
const merged = {
|
|
1630
|
+
...safeBrowserConfig,
|
|
1631
|
+
...safeCommandConfig,
|
|
1632
|
+
...safePreviewOptions,
|
|
1633
|
+
extensions: resolvedExtensionsConfig,
|
|
1634
|
+
chromiumBinary: mergedChromiumBinary,
|
|
1635
|
+
geckoBinary: mergedGeckoBinary
|
|
1636
|
+
};
|
|
1637
|
+
const darkDefaults = withDarkMode({
|
|
1638
|
+
browser,
|
|
1639
|
+
browserFlags: merged.browserFlags,
|
|
1640
|
+
preferences: merged.preferences
|
|
1641
|
+
});
|
|
1642
|
+
const companionUnpackedExtensionDirs = resolveCompanionExtensionDirs({
|
|
1643
|
+
projectRoot: packageJsonDir,
|
|
1644
|
+
config: merged.extensions
|
|
1645
|
+
});
|
|
1646
|
+
const unpackedExtensionDirsToLoad = computeExtensionsToLoad(__rspack_external_path.resolve(command_preview_dirname, '..'), 'production', browser, outputPath, companionUnpackedExtensionDirs, projectStructure.manifestPath);
|
|
1647
|
+
const resolvedOpts = {
|
|
1648
|
+
browser,
|
|
1649
|
+
outPath: outputPath,
|
|
1650
|
+
contextDir: packageJsonDir,
|
|
1651
|
+
readyPath: metadata.readyPath,
|
|
1652
|
+
extensionsToLoad: unpackedExtensionDirsToLoad,
|
|
1653
|
+
noOpen: merged.noOpen,
|
|
1654
|
+
profile: merged.profile,
|
|
1655
|
+
persistProfile: merged.persistProfile,
|
|
1656
|
+
preferences: darkDefaults.preferences,
|
|
1657
|
+
browserFlags: darkDefaults.browserFlags,
|
|
1658
|
+
excludeBrowserFlags: merged.excludeBrowserFlags,
|
|
1659
|
+
startingUrl: merged.startingUrl,
|
|
1660
|
+
chromiumBinary: merged.chromiumBinary,
|
|
1661
|
+
geckoBinary: merged.geckoBinary,
|
|
1662
|
+
instanceId: merged.instanceId,
|
|
1663
|
+
port: merged.port,
|
|
1664
|
+
dryRun: merged.dryRun
|
|
1665
|
+
};
|
|
1666
|
+
if (!browserLauncher) throw new Error("extensionPreview requires a browserLauncher callback. The browser launch code has moved to programs/extension/browsers/.");
|
|
1667
|
+
await browserLauncher(resolvedOpts);
|
|
1668
|
+
metadata.writeReady();
|
|
1669
|
+
}
|
|
1670
|
+
export { PlaywrightPlugin, asAbsolute, assertNoManagedDependencyConflicts, authorInstallNotice, autoExitForceKill, autoExitModeEnabled, autoExitTriggered, browserRunnerDisabled, buildCommandFailed, buildSuccess, buildSuccessWithWarnings, buildWarningsDetails, buildWebpack, bundlerFatalError, bundlerRecompiling, computeExtensionsToLoad, createPlaywrightMetadataWriter, debugBrowser, debugContextPath, debugDirs, debugExtensionsToLoad, debugOutputPath, devServerStartTimeout, downloadingText, extensionJsRunnerError, extensionPreview, failedToDownloadOrExtractZIPFileError, getDirs, getDistPath, getProjectStructure, getSpecialFoldersDataForCompiler, getSpecialFoldersDataForProjectRoot, invalidRemoteZip, loadBrowserConfig, loadCommandConfig, loadCustomConfig, messages_ready, needsInstall, noCompanionExtensionsResolved, noEntrypointsDetected, normalizeBrowser, package_namespaceObject, packagingDistributionFiles, packagingSourceFiles, portInUse, resolveCompanionExtensionsConfig, sanitize, spacerLine, treeWithDistFilesbrowser, treeWithSourceAndDistFiles, treeWithSourceFiles, unpackagedSuccessfully, unpackagingExtension, writingTypeDefinitions, writingTypeDefinitionsError };
|