vite-plugin-cross-origin-storage 1.3.24 → 1.4.1
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/index.js +22 -35
- package/dist/loader.js +38 -18
- package/loader.js +38 -18
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -1619,7 +1619,7 @@ var hasStringIsWellFormed = "isWellFormed" in String.prototype;
|
|
|
1619
1619
|
|
|
1620
1620
|
// index.ts
|
|
1621
1621
|
function cosPlugin(options = {}) {
|
|
1622
|
-
const filter = createFilter(options.include || ["**/*"], options.exclude);
|
|
1622
|
+
const filter = options.include || options.exclude ? createFilter(options.include || ["**/*"], options.exclude, { resolve: false }) : () => true;
|
|
1623
1623
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
1624
1624
|
const loaderPath = path.resolve(__dirname, "./loader.js");
|
|
1625
1625
|
let config;
|
|
@@ -1650,9 +1650,9 @@ function cosPlugin(options = {}) {
|
|
|
1650
1650
|
console.log(`COS Plugin: [ENTRY] ${fileName}`);
|
|
1651
1651
|
mainChunk = chunk;
|
|
1652
1652
|
} else {
|
|
1653
|
-
const res = filter(fileName);
|
|
1653
|
+
const res = filter(fileName) || filter(chunk.name);
|
|
1654
1654
|
console.log(
|
|
1655
|
-
`COS Plugin: [FILTER] ${fileName} -> ${res ? "INCLUDE" : "SKIP"}`
|
|
1655
|
+
`COS Plugin: [FILTER] ${fileName} (name: ${chunk.name}) -> ${res ? "INCLUDE" : "SKIP"}`
|
|
1656
1656
|
);
|
|
1657
1657
|
if (res) {
|
|
1658
1658
|
managedChunks[fileName] = chunk;
|
|
@@ -1668,19 +1668,13 @@ function cosPlugin(options = {}) {
|
|
|
1668
1668
|
(c) => c.type === "chunk"
|
|
1669
1669
|
);
|
|
1670
1670
|
const managedChunkNames = new Set(Object.keys(managedChunks));
|
|
1671
|
+
const unmanagedDependencies = /* @__PURE__ */ new Set();
|
|
1671
1672
|
const base = config.base.endsWith("/") ? config.base : config.base + "/";
|
|
1672
|
-
const managedChunkInfo = {};
|
|
1673
|
-
for (const fileName in managedChunks) {
|
|
1674
|
-
const nameHash = crypto.createHash("sha256").update(fileName).digest("hex").substring(0, 8);
|
|
1675
|
-
managedChunkInfo[fileName] = {
|
|
1676
|
-
globalVar: `__COS_CHUNK_${nameHash}__`,
|
|
1677
|
-
chunk: managedChunks[fileName]
|
|
1678
|
-
};
|
|
1679
|
-
}
|
|
1680
1673
|
for (const targetChunk of allChunks) {
|
|
1681
1674
|
const isTargetManaged = managedChunkNames.has(targetChunk.fileName);
|
|
1682
1675
|
const importerDir = path.dirname(targetChunk.fileName);
|
|
1683
|
-
|
|
1676
|
+
const deps = [...targetChunk.imports, ...targetChunk.dynamicImports];
|
|
1677
|
+
for (const depFileName of deps) {
|
|
1684
1678
|
const depChunk = bundle[depFileName];
|
|
1685
1679
|
if (!depChunk || depChunk.type !== "chunk") continue;
|
|
1686
1680
|
const isDepManaged = managedChunkNames.has(depFileName);
|
|
@@ -1694,45 +1688,38 @@ function cosPlugin(options = {}) {
|
|
|
1694
1688
|
const bareSpecifier = `coschunk-${depFileName.replace(/\//g, "-")}`;
|
|
1695
1689
|
const staticPattern = `(import|export)\\b\\s*((?:(?!\\bimport\\b|\\bexport\\b)[\\s\\S])*?\\bfrom\\b\\s*)?['"]${escapedRelPath}['"]\\s*;?`;
|
|
1696
1690
|
const staticRegex = new RegExp(staticPattern, "g");
|
|
1697
|
-
targetChunk.code = targetChunk.code.replace(
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
return `${keyword}${fromPart ? " " + fromPart : " "}"${bareSpecifier}";`;
|
|
1701
|
-
}
|
|
1702
|
-
);
|
|
1691
|
+
targetChunk.code = targetChunk.code.replace(staticRegex, (match, keyword, fromPart) => {
|
|
1692
|
+
return `${keyword}${fromPart ? " " + fromPart : " "}"${bareSpecifier}";`;
|
|
1693
|
+
});
|
|
1703
1694
|
const dynamicPattern = `import\\s*\\(\\s*['"]${escapedRelPath}['"]\\s*\\)`;
|
|
1704
1695
|
const dynamicRegex = new RegExp(dynamicPattern, "g");
|
|
1705
1696
|
targetChunk.code = targetChunk.code.replace(
|
|
1706
1697
|
dynamicRegex,
|
|
1707
1698
|
() => `import("${bareSpecifier}")`
|
|
1708
1699
|
);
|
|
1700
|
+
if (!isDepManaged) {
|
|
1701
|
+
unmanagedDependencies.add(depFileName);
|
|
1702
|
+
}
|
|
1709
1703
|
}
|
|
1710
1704
|
}
|
|
1711
1705
|
}
|
|
1712
|
-
const manifest = {
|
|
1713
|
-
|
|
1714
|
-
|
|
1706
|
+
const manifest = {
|
|
1707
|
+
base,
|
|
1708
|
+
entry: mainChunk.fileName,
|
|
1709
|
+
chunks: {}
|
|
1710
|
+
};
|
|
1711
|
+
for (const fileName in managedChunks) {
|
|
1712
|
+
const chunk = managedChunks[fileName];
|
|
1715
1713
|
const finalHash = crypto.createHash("sha256").update(chunk.code).digest("hex");
|
|
1716
|
-
|
|
1717
|
-
manifest[fileName] = {
|
|
1718
|
-
fileName,
|
|
1719
|
-
file: `${base}${fileName}`,
|
|
1720
|
-
hash: finalHash,
|
|
1721
|
-
globalVar,
|
|
1722
|
-
hasDefault
|
|
1723
|
-
};
|
|
1714
|
+
manifest.chunks[fileName] = finalHash;
|
|
1724
1715
|
}
|
|
1725
|
-
|
|
1726
|
-
manifest["index"] = {
|
|
1727
|
-
fileName: entryFileName,
|
|
1728
|
-
file: `${base}${entryFileName}`
|
|
1729
|
-
};
|
|
1716
|
+
manifest.unmanaged = Array.from(unmanagedDependencies);
|
|
1730
1717
|
if (htmlAsset) {
|
|
1731
1718
|
try {
|
|
1732
1719
|
let loaderCode = fs.readFileSync(loaderPath, "utf-8");
|
|
1733
1720
|
loaderCode = loaderCode.replace(
|
|
1734
1721
|
"__COS_MANIFEST__",
|
|
1735
|
-
JSON.stringify(manifest)
|
|
1722
|
+
JSON.stringify(manifest, null, 2)
|
|
1736
1723
|
);
|
|
1737
1724
|
let htmlSource = htmlAsset.source;
|
|
1738
1725
|
htmlSource = htmlSource.replace(
|
package/dist/loader.js
CHANGED
|
@@ -6,14 +6,20 @@
|
|
|
6
6
|
// @ts-ignore
|
|
7
7
|
const manifest = __COS_MANIFEST__;
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const { base, entry, chunks } = manifest;
|
|
10
|
+
const mainEntry = entry;
|
|
11
|
+
|
|
10
12
|
if (!mainEntry) {
|
|
11
|
-
console.warn('COS Loader: Missing
|
|
13
|
+
console.warn('COS Loader: Missing entry in manifest.');
|
|
12
14
|
return;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
// Identify managed chunks
|
|
16
|
-
const chunksToLoad = Object.
|
|
17
|
+
// Identify managed chunks
|
|
18
|
+
const chunksToLoad = Object.entries(chunks || {}).map(([fileName, hash]) => ({
|
|
19
|
+
fileName,
|
|
20
|
+
hash,
|
|
21
|
+
file: `${base}${fileName}`,
|
|
22
|
+
}));
|
|
17
23
|
|
|
18
24
|
async function getBlobFromCOS(hash) {
|
|
19
25
|
if (!isCOSAvailable) return null;
|
|
@@ -51,12 +57,17 @@
|
|
|
51
57
|
|
|
52
58
|
async function getChunkDataUrl(chunk) {
|
|
53
59
|
let blob = await getBlobFromCOS(chunk.hash);
|
|
60
|
+
if (blob) {
|
|
61
|
+
console.log(`COS Loader: ${chunk.fileName} found in COS`);
|
|
62
|
+
blob = new Blob([blob], { type: 'text/javascript' });
|
|
63
|
+
}
|
|
54
64
|
if (!blob) {
|
|
55
65
|
console.log(`COS Loader: ${chunk.file} not in COS, fetching...`);
|
|
56
66
|
try {
|
|
57
67
|
const resp = await fetch(chunk.file);
|
|
58
68
|
if (!resp.ok) throw new Error(`Status ${resp.status}`);
|
|
59
|
-
|
|
69
|
+
const rawBlob = await resp.blob();
|
|
70
|
+
blob = new Blob([rawBlob], { type: 'text/javascript' });
|
|
60
71
|
await storeBlobInCOS(blob, chunk.hash);
|
|
61
72
|
} catch (e) {
|
|
62
73
|
console.error(`COS Loader: Failed to fetch ${chunk.file}`, e);
|
|
@@ -64,12 +75,10 @@
|
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
// Convert blob to
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
reader.readAsDataURL(blob);
|
|
72
|
-
});
|
|
78
|
+
// Convert blob to Blob URL
|
|
79
|
+
// Blob URLs are synchronous and share the page origin,
|
|
80
|
+
// which helps with module resolution in complex graphs.
|
|
81
|
+
return URL.createObjectURL(blob);
|
|
73
82
|
}
|
|
74
83
|
|
|
75
84
|
// Initialize
|
|
@@ -78,6 +87,14 @@
|
|
|
78
87
|
|
|
79
88
|
// Resolve all chunks to Data URLs
|
|
80
89
|
const importMap = { imports: {} };
|
|
90
|
+
|
|
91
|
+
// Set up unmanaged dependencies correctly so Data URLs can resolve them.
|
|
92
|
+
for (const fileName of manifest.unmanaged || []) {
|
|
93
|
+
const bareSpecifier = `coschunk-${fileName.replace(/\//g, '-')}`;
|
|
94
|
+
importMap.imports[bareSpecifier] = window.location.origin + base + fileName;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log(`COS Loader: Loading ${chunksToLoad.length} chunks...`);
|
|
81
98
|
const loadPromises = chunksToLoad.map(async (chunk) => {
|
|
82
99
|
const dataUrl = await getChunkDataUrl(chunk);
|
|
83
100
|
if (dataUrl) {
|
|
@@ -93,19 +110,22 @@
|
|
|
93
110
|
// Inject Import Map
|
|
94
111
|
const script = document.createElement('script');
|
|
95
112
|
script.type = 'importmap';
|
|
96
|
-
script.textContent = JSON.stringify(importMap);
|
|
113
|
+
script.textContent = JSON.stringify(importMap, null, 2);
|
|
97
114
|
document.head.appendChild(script);
|
|
98
115
|
|
|
99
116
|
console.log('COS Loader: Import Map injected');
|
|
100
117
|
|
|
101
118
|
// Import the main entry.
|
|
102
|
-
|
|
103
|
-
// For now, it's loaded via its absolute path from the server,
|
|
104
|
-
// and its internal imports (rewritten by the plugin) will use cos-chunk:
|
|
105
|
-
const entryUrl = mainEntry.file;
|
|
106
|
-
await import(entryUrl);
|
|
119
|
+
const entryUrl = `${base}${mainEntry}`;
|
|
107
120
|
|
|
121
|
+
// Small delay to ensure the browser has fully registered the
|
|
122
|
+
// import map before resolving the first module.
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
import(entryUrl).catch((err) => {
|
|
125
|
+
console.error('COS Loader: Failed to start app', err);
|
|
126
|
+
});
|
|
127
|
+
}, 0);
|
|
108
128
|
} catch (err) {
|
|
109
|
-
console.error('COS Loader:
|
|
129
|
+
console.error('COS Loader: Initialization failed', err);
|
|
110
130
|
}
|
|
111
131
|
})();
|
package/loader.js
CHANGED
|
@@ -6,14 +6,20 @@
|
|
|
6
6
|
// @ts-ignore
|
|
7
7
|
const manifest = __COS_MANIFEST__;
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const { base, entry, chunks } = manifest;
|
|
10
|
+
const mainEntry = entry;
|
|
11
|
+
|
|
10
12
|
if (!mainEntry) {
|
|
11
|
-
console.warn('COS Loader: Missing
|
|
13
|
+
console.warn('COS Loader: Missing entry in manifest.');
|
|
12
14
|
return;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
// Identify managed chunks
|
|
16
|
-
const chunksToLoad = Object.
|
|
17
|
+
// Identify managed chunks
|
|
18
|
+
const chunksToLoad = Object.entries(chunks || {}).map(([fileName, hash]) => ({
|
|
19
|
+
fileName,
|
|
20
|
+
hash,
|
|
21
|
+
file: `${base}${fileName}`,
|
|
22
|
+
}));
|
|
17
23
|
|
|
18
24
|
async function getBlobFromCOS(hash) {
|
|
19
25
|
if (!isCOSAvailable) return null;
|
|
@@ -51,12 +57,17 @@
|
|
|
51
57
|
|
|
52
58
|
async function getChunkDataUrl(chunk) {
|
|
53
59
|
let blob = await getBlobFromCOS(chunk.hash);
|
|
60
|
+
if (blob) {
|
|
61
|
+
console.log(`COS Loader: ${chunk.fileName} found in COS`);
|
|
62
|
+
blob = new Blob([blob], { type: 'text/javascript' });
|
|
63
|
+
}
|
|
54
64
|
if (!blob) {
|
|
55
65
|
console.log(`COS Loader: ${chunk.file} not in COS, fetching...`);
|
|
56
66
|
try {
|
|
57
67
|
const resp = await fetch(chunk.file);
|
|
58
68
|
if (!resp.ok) throw new Error(`Status ${resp.status}`);
|
|
59
|
-
|
|
69
|
+
const rawBlob = await resp.blob();
|
|
70
|
+
blob = new Blob([rawBlob], { type: 'text/javascript' });
|
|
60
71
|
await storeBlobInCOS(blob, chunk.hash);
|
|
61
72
|
} catch (e) {
|
|
62
73
|
console.error(`COS Loader: Failed to fetch ${chunk.file}`, e);
|
|
@@ -64,12 +75,10 @@
|
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
// Convert blob to
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
reader.readAsDataURL(blob);
|
|
72
|
-
});
|
|
78
|
+
// Convert blob to Blob URL
|
|
79
|
+
// Blob URLs are synchronous and share the page origin,
|
|
80
|
+
// which helps with module resolution in complex graphs.
|
|
81
|
+
return URL.createObjectURL(blob);
|
|
73
82
|
}
|
|
74
83
|
|
|
75
84
|
// Initialize
|
|
@@ -78,6 +87,14 @@
|
|
|
78
87
|
|
|
79
88
|
// Resolve all chunks to Data URLs
|
|
80
89
|
const importMap = { imports: {} };
|
|
90
|
+
|
|
91
|
+
// Set up unmanaged dependencies correctly so Data URLs can resolve them.
|
|
92
|
+
for (const fileName of manifest.unmanaged || []) {
|
|
93
|
+
const bareSpecifier = `coschunk-${fileName.replace(/\//g, '-')}`;
|
|
94
|
+
importMap.imports[bareSpecifier] = window.location.origin + base + fileName;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log(`COS Loader: Loading ${chunksToLoad.length} chunks...`);
|
|
81
98
|
const loadPromises = chunksToLoad.map(async (chunk) => {
|
|
82
99
|
const dataUrl = await getChunkDataUrl(chunk);
|
|
83
100
|
if (dataUrl) {
|
|
@@ -93,19 +110,22 @@
|
|
|
93
110
|
// Inject Import Map
|
|
94
111
|
const script = document.createElement('script');
|
|
95
112
|
script.type = 'importmap';
|
|
96
|
-
script.textContent = JSON.stringify(importMap);
|
|
113
|
+
script.textContent = JSON.stringify(importMap, null, 2);
|
|
97
114
|
document.head.appendChild(script);
|
|
98
115
|
|
|
99
116
|
console.log('COS Loader: Import Map injected');
|
|
100
117
|
|
|
101
118
|
// Import the main entry.
|
|
102
|
-
|
|
103
|
-
// For now, it's loaded via its absolute path from the server,
|
|
104
|
-
// and its internal imports (rewritten by the plugin) will use cos-chunk:
|
|
105
|
-
const entryUrl = mainEntry.file;
|
|
106
|
-
await import(entryUrl);
|
|
119
|
+
const entryUrl = `${base}${mainEntry}`;
|
|
107
120
|
|
|
121
|
+
// Small delay to ensure the browser has fully registered the
|
|
122
|
+
// import map before resolving the first module.
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
import(entryUrl).catch((err) => {
|
|
125
|
+
console.error('COS Loader: Failed to start app', err);
|
|
126
|
+
});
|
|
127
|
+
}, 0);
|
|
108
128
|
} catch (err) {
|
|
109
|
-
console.error('COS Loader:
|
|
129
|
+
console.error('COS Loader: Initialization failed', err);
|
|
110
130
|
}
|
|
111
131
|
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-cross-origin-storage",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Vite plugin to load chunks from Cross-Origin Storage",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vite",
|
|
@@ -36,7 +36,10 @@
|
|
|
36
36
|
],
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "tsup index.ts --format esm --dts --clean && cp loader.js dist/",
|
|
39
|
-
"prepublishOnly": "npm run build"
|
|
39
|
+
"prepublishOnly": "npm run build",
|
|
40
|
+
"test:dev": "npm run build && vite testing",
|
|
41
|
+
"test:build": "npm run build && vite build testing",
|
|
42
|
+
"test:preview": "vite preview testing"
|
|
40
43
|
},
|
|
41
44
|
"peerDependencies": {
|
|
42
45
|
"vite": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|