problem to import per dependencies and commonjs
misaku opened this issue · comments
- SystemJS Version:
- Which library are you using?
- system.js
- s.js
- system-node.cjs
- Which extras are you using?
- AMD extra
- Named Exports
- Named Register
- Transform
- Use Default
- Global
- Dynamic Import Maps
- Are you using any custom hooks?
single-spa
Question
i heve few problens with imports cdns.
example i tryed to impotr zustand, but zustand need per dependecies zustand/vanilla, and i import too, but now need per dependencies use-sync-external-store/shim/with-selector and this lib is cjs, becouse it my application is broken.
i would like know if have correct import with automatic dependencies and how can i solve problem with cjs?
@misaku suggest you to use the jspm, here is my poc, after the plugin loaded you can just System.import('npm:zustand')
npm resolver
const orig = (System as any).instantiate.bind(System);
const cache = new Map<string, string>();
(System as any).instantiate = async function (url: string, parent: string) {
const loader = this as ModuleSystem;
console.debug(`instantiate`, url, parent);
let next = url;
if (url.startsWith('npm:')) {
if (cache.has(url)) {
return orig(cache.get(url), parent);
}
// @wener/reaction -> @wener/reaction@1.2.11
// @wener/reaction@latest -> @wener/reaction@1.2.11
// @wener/reaction@^1 -> @wener/reaction@1.2.11
// resolve the version by jsdelivr
// cache the package.json for later use
// https://cdn.jsdelivr.net/npm/@@wener/reaction@latest/package.json
// https://ga.system.jspm.io/npm:@wener/reaction@1.2.11/package.json
let repo = new URL(url).pathname;
let {
name,
ver,
path = '',
} = repo.match(/^(?<name>@[^/]+\/[^/@]+|[^/@]+)(@(?<ver>[^/]+))?(?<path>\/.*)?$/)?.groups || {};
if (!ver || /^\D/.test(ver)) {
ver ||= 'latest';
// just resolve the version, ignore path
const p = `https://cdn.jsdelivr.net/npm/${name}@${ver}/package.json`;
const mod = await loader.import(p);
repo = `${name}@${mod.default.version}${path}`;
// already load
loader.set(`https://ga.system.jspm.io/npm:${repo}`, mod);
}
next = `https://ga.system.jspm.io/npm:${repo}`;
// /lib -> /lib/package.json -> .module, .import, .main
// /lib -> /lib/index.js
// /lib -> /lib.js
// /package.json -> .exports - TODO
if (!/.(json|js)$/.test(next)) {
try {
const pkg = next + '/package.json';
console.debug(`load package.json`, url, parent, pkg);
const { default: p } = await loader.import(pkg);
// can be improved to use the exports
const to = p.module || p.import || p.main;
if (to) {
next = new URL(to, next + '/').toString();
}
console.debug(`resolve pkg`, next, p);
} catch (e) {
console.error(`load package.json failed`, e);
// better check the exports to avoid try and fail
try {
await loader.import(next + '/index.js');
next += '/index.js';
} catch (e) {
try {
await loader.import(next + '.js');
next += '.js';
} catch (e) {
throw new Error(`resolve ${url} failed`);
}
}
}
}
}
let result = orig(next, parent);
if ('then' in result) {
return result.then((v: any) => {
if (url.startsWith('npm:')) {
console.debug(`cache npm resolve:`, url, next);
cache.set(url, next);
}
return v;
});
}
return result;
};
but this plugin will not handle use-sync-external-store/shim/with-selector
. for internal deps I suggest you manual load to prevent the multi version of core lib.
// lazy reexport
const BuiltinModules: Record<string, () => Promise<any>> = {
// react
react: () => import('react'),
scheduler: () => import('scheduler'),
'react/jsx-runtime': () => import('react/jsx-runtime'),
'react-is': () => import('react-is'),
'use-sync-external-store/shim/with-selector': () => import('use-sync-external-store/shim/with-selector' as any),
'react-dom': () => import('react-dom'),
}
export function registerBuiltinModules(s: ModuleSystem) {
Object.entries(BuiltinModules).map(([k, v]) => {
// if mapped use s.resolve(k)
s.register(k, [], (exports, module) => {
return {
execute: async () => {
if (process.env.NODE_ENV !== 'production') {
console.debug(`Loading builtin module ${k}`);
}
exports(await v());
},
};
});
});
}
the resolve process can be improved.