Open lionel-rowe opened 1 year ago
For anyone looking for a workaround to this issue in Deno Deploy, check out https://github.com/ayoreis/import.
With it, you can dynamically import non-statically-analyzable modules; import code from string and even a code string that imports another module dynamically inside it.
import { importString, importModule } from "https://deno.land/x/import/mod.ts";
let { default: renderer } = await importString(`
const renderer = async ()=>{
const { render } = await modules.importModule('https://deno.land/x/mustache_ts/mustache.ts');
const template = '{{foo}}, {{bar}}!'
const view = {
foo: 'Hello',
bar: 'World!'
}
const output = render(template, view)
return output;
};
export default renderer;
`,
{ modules: { importModule } },
)
console.log(await renderer()) // expected: "Hello, World!"
Another workaround inspired by a nice trick someone posted on the discord
Assuming you want to achieve something similar to this:
const {mod} = await import(`./routes/${url.pathname}`)
You can make something that has a similar behavior to the --include
flags from deno compile
(i.e. include additional modules you know you may use later ahead of time) by doing this:
(async () => await import("./routes/a.ts"));
(async () => await import("./routes/b.ts"));
(async () => await import("./routes/c.ts"));
Basically these are async functions which are not called (so not executed meaning they are no-op) but the analyzer will still resolve these imports during deployment, making them loadable dynamically later on
If you want to automate a bit things, you can even generate these definitions using something like an expandGlob("**/*.ts")
and run this as a build step or pre-commit
This alternative has the advantage of being somewhat "native" as it uses deno deploy own resolution/loading system
Thanks for the comment @lowlighter .. I wrote a simple shell script, run it as a step in Github Actions to find all of the files and append the await import
lines to the code which is performing the dynamic imports. Deno Deploy static analysis sees the imports, the files are kept, and the dynamic imports are working! 🚀
As things stand, importing from dynamically created data:
URIs does work, including if they import other (statically analyzable) packages, e.g.
// Import in a statically analyzable way
import('npm:<some-npm-package>@1.2.3')
// then, later on...
await import(
`data:text/javascript;base64,${
encodeBase64(`
import * as mod from 'npm:<some-npm-package>@1.2.3'
console.log(mod)
console.log(${Math.random()})
`)
}`
)
But it doesn't work if you try to dedupe the package version by un-hard-coding it, even if it's a simple string declared with const
in the same file:
const PACKAGE_VERSION = 'npm:<some-npm-package>@1.2.3'
// next line fails
import(PACKAGE_VERSION)
await import(
`data:text/javascript;base64,${
encodeBase64(`
import * as mod from '${PACKAGE_VERSION}'
console.log(mod)
`)
}`
)
Not sure if it'd be feasible to enable relatively simple cases like this as an intermediate step toward full dynamic imports, but I have a use case where it'd be useful.
What problem are you trying to solve?
Separate tracking issue for non-statically-analyzable dynamic imports, as the fix for #1 Dynamic imports only solves statically-analyzable use cases.
Among other use cases, this would be useful for framework authors wishing to skip build steps entirely; without this feature, at a minimum, a file containing literal paths for routes/components has to be generated.
Example (currently possible in Deno, but not on Deno Deploy):
Describe the solution you'd like
{ assert: { type: 'json' } }
) file types (is this list exhaustive?)Describe alternatives you've considered
A partial solution could involve only supporting js/json files, with transpilation not supported. However, my guess is that wouldn't support most use cases, as most developers using Deno primarily author in TypeScript.
Documentation, Adoption, Migration Strategy
No response