vite-plugin-cross-origin-storage 1.5.0 → 1.6.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/index.js CHANGED
@@ -1654,14 +1654,12 @@ function cosPlugin(options = {}) {
1654
1654
  if (pkgName) {
1655
1655
  try {
1656
1656
  require2.resolve(pkgName);
1657
- const externalPatterns = [pkgName, `${pkgName}/*`];
1658
- for (const pattern of externalPatterns) {
1659
- if (!externalArray.includes(pattern)) {
1660
- console.log(
1661
- `COS Plugin: [MAGIC] Externalizing pattern "${pattern}" (matched from ${item})`
1662
- );
1663
- externalArray.push(pattern);
1664
- }
1657
+ const pkgRegex = new RegExp(`^${pkgName}(?:/.*)?$`);
1658
+ if (!externalArray.some((e) => e instanceof RegExp && e.source === pkgRegex.source)) {
1659
+ console.log(
1660
+ `COS Plugin: [MAGIC] Externalizing package and subpaths: ${pkgRegex} (matched from ${item})`
1661
+ );
1662
+ externalArray.push(pkgRegex);
1665
1663
  }
1666
1664
  } catch (e) {
1667
1665
  }
@@ -1719,40 +1717,40 @@ function cosPlugin(options = {}) {
1719
1717
  }
1720
1718
  return null;
1721
1719
  }
1720
+ const magicPackages = /* @__PURE__ */ new Set();
1722
1721
  for (const item of includeArray) {
1723
1722
  const pkgName = getPackageName(item);
1724
- if (!pkgName) continue;
1725
- try {
1726
- let pkgPath = "";
1723
+ if (pkgName) {
1727
1724
  try {
1728
- const mainPath = require2.resolve(pkgName);
1729
- let currentDir = path.dirname(mainPath);
1730
- let pkgJsonPath = "";
1731
- while (currentDir !== path.parse(currentDir).root) {
1732
- const candidate = path.join(currentDir, "package.json");
1733
- if (fs.existsSync(candidate)) {
1734
- pkgJsonPath = candidate;
1735
- break;
1736
- }
1737
- currentDir = path.dirname(currentDir);
1738
- }
1739
- if (pkgJsonPath) {
1740
- const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
1741
- const pkgDir = path.dirname(pkgJsonPath);
1742
- if (pkgJson.module) {
1743
- pkgPath = path.resolve(pkgDir, pkgJson.module);
1744
- } else if (pkgJson.exports?.["."]?.import) {
1745
- pkgPath = path.resolve(pkgDir, pkgJson.exports["."].import);
1746
- } else if (pkgJson.exports?.import) {
1747
- pkgPath = path.resolve(pkgDir, pkgJson.exports.import);
1748
- }
1749
- }
1750
- if (!pkgPath) {
1751
- pkgPath = mainPath;
1752
- }
1725
+ require2.resolve(pkgName);
1726
+ magicPackages.add(pkgName);
1753
1727
  } catch (e) {
1754
- pkgPath = require2.resolve(pkgName);
1755
1728
  }
1729
+ }
1730
+ }
1731
+ const discoveredSpecifiers = /* @__PURE__ */ new Set();
1732
+ const allChunks = Object.values(bundle).filter(
1733
+ (c) => c.type === "chunk"
1734
+ );
1735
+ for (const chunk of allChunks) {
1736
+ const allImports = [...chunk.imports, ...chunk.dynamicImports];
1737
+ for (const specifier of allImports) {
1738
+ for (const pkgName of magicPackages) {
1739
+ if (specifier === pkgName || specifier.startsWith(`${pkgName}/`)) {
1740
+ discoveredSpecifiers.add(specifier);
1741
+ break;
1742
+ }
1743
+ }
1744
+ }
1745
+ }
1746
+ const specifierToCode = {};
1747
+ for (const specifier of discoveredSpecifiers) {
1748
+ try {
1749
+ const pkgPath = require2.resolve(specifier);
1750
+ const pkgName = Array.from(magicPackages).find((p) => specifier === p || specifier.startsWith(`${p}/`));
1751
+ const otherSpecifiersFromSamePkg = Array.from(discoveredSpecifiers).filter(
1752
+ (s) => s !== specifier && (s === pkgName || s.startsWith(`${pkgName}/`))
1753
+ );
1756
1754
  const esbuildRequire = createRequire(import.meta.url);
1757
1755
  const esbuild = esbuildRequire("esbuild");
1758
1756
  const buildResult = await esbuild.build({
@@ -1762,19 +1760,32 @@ function cosPlugin(options = {}) {
1762
1760
  minify: true,
1763
1761
  platform: "browser",
1764
1762
  write: false,
1765
- // Don't write to disk
1766
1763
  target: "esnext",
1767
- // Neutralize environment
1764
+ // Mark other components of the same library as external to avoid duplication
1765
+ external: otherSpecifiersFromSamePkg,
1768
1766
  define: {
1769
1767
  "process.env.NODE_ENV": '"production"'
1770
1768
  }
1771
1769
  });
1772
- const content = buildResult.outputFiles[0].contents;
1770
+ let code = buildResult.outputFiles[0].text;
1771
+ for (const otherSpec of otherSpecifiersFromSamePkg) {
1772
+ const escapedOtherSpec = otherSpec.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1773
+ const bareSpecifier = `coschunk-${otherSpec.replace(/[/@]/g, "-")}`;
1774
+ const staticRegex = new RegExp(`(import|export)\\b\\s*((?:(?!\\bimport\\b|\\bexport\\b)[\\s\\S])*?\\bfrom\\b\\s*)?['"]${escapedOtherSpec}['"]\\s*;?`, "g");
1775
+ code = code.replace(staticRegex, (match, keyword, fromPart) => {
1776
+ return `${keyword}${fromPart ? " " + fromPart : " "}"${bareSpecifier}";`;
1777
+ });
1778
+ const dynamicRegex = new RegExp(`import\\s*\\(\\s*['"]${escapedOtherSpec}['"]\\s*\\)`, "g");
1779
+ code = code.replace(dynamicRegex, () => `import("${bareSpecifier}")`);
1780
+ }
1781
+ specifierToCode[specifier] = code;
1782
+ const content = Buffer.from(code);
1773
1783
  const hash = crypto.createHash("sha256").update(content).digest("hex");
1774
- const ext = path.extname(pkgPath);
1784
+ const ext = ".js";
1785
+ const safeSpecifier = specifier.replace(/[/@]/g, "-").replace(/\.js$/, "");
1775
1786
  const fileName = path.join(
1776
1787
  config.build.assetsDir,
1777
- `${pkgName}-${hash.slice(0, 8)}${ext}`
1788
+ `${safeSpecifier}-${hash.slice(0, 8)}${ext}`
1778
1789
  );
1779
1790
  this.emitFile({
1780
1791
  type: "asset",
@@ -1784,21 +1795,27 @@ function cosPlugin(options = {}) {
1784
1795
  managedChunks[fileName] = {
1785
1796
  type: "chunk",
1786
1797
  fileName,
1787
- code: content.toString(),
1788
- name: item
1798
+ code,
1799
+ name: specifier
1789
1800
  };
1790
- externalToFileName[pkgName] = fileName;
1801
+ externalToFileName[specifier] = fileName;
1791
1802
  } catch (e) {
1803
+ console.error(`COS Plugin: Failed to bundle magic specifier "${specifier}"`, e);
1792
1804
  }
1793
1805
  }
1794
1806
  if (mainChunk) {
1795
- const allChunks = Object.values(bundle).filter(
1807
+ const magicMapping = {};
1808
+ for (const specifier in externalToFileName) {
1809
+ const bareSpecifier = `coschunk-${specifier.replace(/[/@]/g, "-")}`;
1810
+ magicMapping[bareSpecifier] = externalToFileName[specifier];
1811
+ }
1812
+ const allChunks2 = Object.values(bundle).filter(
1796
1813
  (c) => c.type === "chunk"
1797
1814
  );
1798
1815
  const managedChunkNames = new Set(Object.keys(managedChunks));
1799
1816
  const unmanagedDependencies = /* @__PURE__ */ new Set();
1800
1817
  const base = config.base.endsWith("/") ? config.base : config.base + "/";
1801
- for (const targetChunk of allChunks) {
1818
+ for (const targetChunk of allChunks2) {
1802
1819
  const importerDir = path.dirname(targetChunk.fileName);
1803
1820
  const deps = [...targetChunk.imports, ...targetChunk.dynamicImports];
1804
1821
  for (const depFileName of deps) {
@@ -1831,8 +1848,7 @@ function cosPlugin(options = {}) {
1831
1848
  }
1832
1849
  }
1833
1850
  for (const pkgName in externalToFileName) {
1834
- const fileName = externalToFileName[pkgName];
1835
- const bareSpecifier = `coschunk-${fileName.replace(/\//g, "-")}`;
1851
+ const bareSpecifier = `coschunk-${pkgName.replace(/[/@]/g, "-")}`;
1836
1852
  const staticPattern = `(import|export)\\b\\s*((?:(?!\\bimport\\b|\\bexport\\b)[\\s\\S])*?\\bfrom\\b\\s*)?['"]${pkgName}['"]\\s*;?`;
1837
1853
  const staticRegex = new RegExp(staticPattern, "g");
1838
1854
  targetChunk.code = targetChunk.code.replace(
@@ -1852,7 +1868,8 @@ function cosPlugin(options = {}) {
1852
1868
  const manifest = {
1853
1869
  base,
1854
1870
  entry: mainChunk.fileName,
1855
- chunks: {}
1871
+ chunks: {},
1872
+ magic: magicMapping
1856
1873
  };
1857
1874
  for (const fileName in managedChunks) {
1858
1875
  const chunk = managedChunks[fileName];
package/dist/loader.js CHANGED
@@ -111,6 +111,18 @@
111
111
  // Inject Import Map
112
112
  const script = document.createElement('script');
113
113
  script.type = 'importmap';
114
+
115
+ // Add magic specifier mappings (e.g. coschunk-three -> assets/three-*.js)
116
+ if (manifest.magic) {
117
+ for (const [specifier, fileName] of Object.entries(manifest.magic)) {
118
+ const targetSpecifier = `coschunk-${fileName.replace(/\//g, '-')}`;
119
+ const targetUrl = importMap.imports[targetSpecifier];
120
+ if (targetUrl) {
121
+ importMap.imports[specifier] = targetUrl;
122
+ }
123
+ }
124
+ }
125
+
114
126
  script.textContent = JSON.stringify(importMap, null, 2);
115
127
  document.head.appendChild(script);
116
128
 
package/loader.js CHANGED
@@ -111,6 +111,18 @@
111
111
  // Inject Import Map
112
112
  const script = document.createElement('script');
113
113
  script.type = 'importmap';
114
+
115
+ // Add magic specifier mappings (e.g. coschunk-three -> assets/three-*.js)
116
+ if (manifest.magic) {
117
+ for (const [specifier, fileName] of Object.entries(manifest.magic)) {
118
+ const targetSpecifier = `coschunk-${fileName.replace(/\//g, '-')}`;
119
+ const targetUrl = importMap.imports[targetSpecifier];
120
+ if (targetUrl) {
121
+ importMap.imports[specifier] = targetUrl;
122
+ }
123
+ }
124
+ }
125
+
114
126
  script.textContent = JSON.stringify(importMap, null, 2);
115
127
  document.head.appendChild(script);
116
128
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-cross-origin-storage",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Vite plugin to load chunks from Cross-Origin Storage",
5
5
  "keywords": [
6
6
  "vite",