Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic imports #1

Closed
newtack opened this issue Apr 2, 2021 · 29 comments
Closed

Dynamic imports #1

newtack opened this issue Apr 2, 2021 · 29 comments

Comments

@newtack
Copy link

newtack commented Apr 2, 2021

I know this is not supported today, but would love to see this being supported in the future.

Use case: We have a dynamic server rendered web server where we use configuration and dynamic imports based on that configuration to fetch the relevant page handler.

@WardCunningham
Copy link

Federated wiki uses dynamic imports for rarely used or newly created item formatting plugins. We haven't yet figured out exactly how Deploy helps us, perhaps as insolation from older or non-compliant browsers. We usually stop thinking these things when we remember we can't load plugins.

@Industrial
Copy link

I'm trying to get https://github.com/exhibitionist-digital/ultra deployed (react 18, streaming SSR) but after forking it and removing the import maps I found that it uses dynamic imports, so it's currently not possible to deploy with.

@nnmrts
Copy link

nnmrts commented Nov 20, 2021

@Industrial Same...I don't really see the reason for dynamic import being disabled, but I'm also not a backend expert.

I tried a lot of things but I eventually gave up and now use a DigitalOcean Droplet...but a Deno Deploy solution would be really awesome, not just because of the money I now have to pay for DO, but because Deno Deploy is so easy and fast to work with.

@mashaal
Copy link

mashaal commented Feb 23, 2022

I can see why dynamic imports of remote libs may be unwanted, but there is a lot of value in the ability to dynamically import local modules. Modern frontend frameworks could then have native code-splitting -- importing route and component files as needed, like @newtack explained above.

Libraries like React and Solid are now supporting dynamic imports. It currently does work in Deno when server side rendering, so I imagine we will be seeing more of this in the near future: https://reactjs.org/docs/code-splitting.html#reactlazy

Maybe we could declare all remote libs in an importmap -- then only allow local modules to be imported?

@Industrial I did push and update to https://github.com/exhibitionist-digital/ultra which allows deployment to Deno Deploy, but yes, you need to ensure you don't actually use dynamic imports in your codebase.

@BrunoBernardino
Copy link

Here's an example similar to the situation as OP that doesn't work right now in Deno Deploy: https://github.com/BrunoBernardino/deno-boilerplate-simple-website/blob/5d32fb081d6080564e91a8ca8fdd6921ab9420cc/routes.ts#L31-L35

This means the alternative is to load all pages even if they're not going to be needed, so that it works in Deno Deploy: https://github.com/BrunoBernardino/deno-boilerplate-simple-website/blob/5d32fb081d6080564e91a8ca8fdd6921ab9420cc/routes.ts#L4-L12

Not having this functionality means it'll be impossible for any similar performance logic to be used with Deno Deploy, which seems like a shame.

@johnhenry
Copy link

Not having dynamic imports prevents this from working: https://github.com/withastro/astro/tree/main/packages/integrations/deno

@ayoreis
Copy link

ayoreis commented Apr 29, 2022

I'm building an web library (imagine React but 100× better) but would need Dynamic imports for async importing of data URLs. Of course works in Deno, but I would also like it to deployable to Deno Deploy. Would be great if you'd add this! Thanks.

fusionstrings added a commit to jspm/jspm-packages that referenced this issue May 4, 2022
* add version selector

* dynamix import not supported in Deno deploy...so

denoland/deploy_feedback#1
@Wolven531
Copy link

For those that land here from GQL (https://doc.deno.land/https://deno.land/x/gql@1.1.1/mod.ts or https://deno.land/x/gql@1.1.1), to avoid using the dynamic import in this module, I created a local version of the GraphQLHTTP function whose ONLY change is the dynamic import being changed to non-dynamic. The source is below

import {
	GQLOptions,
	runHttpQuery,
} from 'https://deno.land/x/gql@1.1.1/common.ts';
import { renderPlaygroundPage } from 'https://deno.land/x/gql@1.1.1/graphiql/render.ts';
import type { GQLRequest } from 'https://deno.land/x/gql@1.1.1/types.ts';

// !!! all code below is from https://deno.land/x/gql@1.1.1/http.ts
// except for removal of dynamic import

/**
 * Create a new GraphQL HTTP middleware with schema, context etc
 * @param {GQLOptions} options
 *
 * @example
 * ```ts
 * const graphql = await GraphQLHTTP({ schema })
 *
 * for await (const req of s) graphql(req)
 * ```
 */
export function GraphQLHTTP<
	Req extends GQLRequest = GQLRequest,
	Ctx extends { request: Req } = { request: Req },
>({
	playgroundOptions = {},
	headers = {},
	...options
}: GQLOptions<Ctx, Req>) {
	return async (request: Req) => {
		if (options.graphiql && request.method === 'GET') {
			if (request.headers.get('Accept')?.includes('text/html')) {
				// !!! only modified portion is here
				// const { renderPlaygroundPage } = await import(
				// 	"./graphiql/render.ts"
				// );
				// !!! end of modified portion
				const playground = renderPlaygroundPage({
					...playgroundOptions,
					endpoint: '/graphql',
				});

				return new Response(playground, {
					headers: new Headers({
						'Content-Type': 'text/html',
						...headers,
					}),
				});
			} else {
				return new Response(
					'"Accept" header value must include text/html',
					{
						status: 400,

						headers: new Headers(headers),
					},
				);
			}
		} else {
			if (!['PUT', 'POST', 'PATCH'].includes(request.method)) {
				return new Response('Method Not Allowed', {
					status: 405,
					headers: new Headers(headers),
				});
			} else {
				try {
					const result = await runHttpQuery<Req, Ctx>(
						await request.json(),
						options,
						{ request },
					);

					return new Response(JSON.stringify(result, null, 2), {
						status: 200,
						headers: new Headers({
							'Content-Type': 'application/json',
							...headers,
						}),
					});
				} catch (e) {
					console.error(e);
					return new Response('Malformed request body', {
						status: 400,
						headers: new Headers(headers),
					});
				}
			}
		}
	};
}

@brundonsmith
Copy link

brundonsmith commented Jun 22, 2022

Any movement on this? It's keeping me from using Deno Deploy for a project


Edit: I came up with a workaround; I'll share it here for others that may be stuck.

My situation is one where I didn't strictly need dynamic imports (the modules to be imported all exist in source control), I just wanted to import them dynamically for ergonomics; when I add a new file in a certain directory, I want it to be picked up without going and manually configuring it to be loaded.

What I did as a workaround is I wrote a script to walk that directory and generate a TypeScript file that statically imports all the relevant modules, and re-exports their contents in a way where they can be looked up by module path. This manifest is then checked into source control, so by the time it gets to Deno Deploy everything is static. Hopefully I'll be able to drop this mechanism one day.

You can see it here: https://github.com/brundonsmith/site/blob/master/routes-manifest-generate.ts

@orta
Copy link

orta commented Jul 15, 2022

I'm hitting this because I need to set up a bunch of node-y / browser-y globals before my app's code is loaded due to a library not supporting deno - Azure/azure-sdk-for-js#13281 (comment) (gonna look into getting this uncoupled though dropped the dep by re-creating it in fetch myself, leaving the comment because it is still a legit case for why you might need the dynamic import)

@yidingww
Copy link

Any progress on this? I am hitting this problem too when using presetWebFonts from UnoCSS

screenshot

@5310
Copy link

5310 commented Jul 16, 2022

It's been over a year. This was the first issue created on this repository. If we were going to get a response, we would've gotten one by now.

@MarkBennett
Copy link

Has anyone tried out this ponyfill? It claims to let you import from a string on Deno Deploy.

https://github.com/ayoreis/import

@nnmrts
Copy link

nnmrts commented Sep 9, 2022

@MarkBennett Looking at the code, it should generally work. But as soon as you need to rely on anything related to module resolving or the module metadata itself (stuff like import.meta.main), it probably breaks or becomes a bit less usable, although I haven't tried it out yet. vscode is probably unable to know about files being "imported" like that.

Also it bundles everything into one big function, which could lead to code being duplicated.

zaiste added a commit to kreteshq/kretes that referenced this issue Oct 16, 2022
Generate a route manifest to make it deployable on Deno Deploy.
Inspired by Fresh [1] and Deno Deploy limitations [2]

[1]: https://github.com/denoland/fresh
[2]: denoland/deploy_feedback#1
@mashaal
Copy link

mashaal commented Nov 11, 2022

Ultra 2.1.0 has an option to inline server dynamic imports while still retaining client side dynamic usage. Both with React.lazy and await import.

If this helps anyone else: exhibitionist-digital/ultra#195

@gnestor
Copy link

gnestor commented Dec 10, 2022

I'm trying to run Observable notebooks in Deno so that I can write client and server-side code in notebooks. I prefer to import notebooks dynamically vs. maintaining a bunch of static imports somewhere in my Deno code. I have no issues when running my Deno script locally, but when I try to run them in Deno Deploy, I get:

TypeError: Dynamic import is not enabled in this context.
    at async getNotebook (file:///src/observable.ts:29:31)

Are there any workarounds? I don't think it's possible to eval ES module code. I tried https://github.com/ayoreis/import but it's not working for me. If not, it looks like I'll have to use Cloudflare Workers or some other cloud provider.

@BrunoBernardino
Copy link

BrunoBernardino commented Dec 10, 2022

@gnestor The "easiest" workaround would be to do what fresh does: run some script to generate the static imports based on a dynamic list/way, and then deploy.

I've been using Deno Deploy since its inception and honestly it just doesn't work when things "get going". I need to move into fly.io for that (another example is that Cache just isn't available on Deploy and isn't planned for a few more months), or some other alternative, which is a shame.

@gnestor
Copy link

gnestor commented Dec 11, 2022

@BrunoBernardino Thanks for that suggestion. There will be cases where I want to run cells from a new notebook that's not included in the source, in which case I would need to re-run the script and update the source, which is doable but not ideal.

I was able to work around this by using https://github.com/ayoreis/import and patching it: ayoreis/import#10 (comment)

https://github.com/ayoreis/import works by essentially fetching the source code of the module, using esbuild to convert it into non-module Javascript, and creating an async function instance using it. If the native import function is available in the runtime (not Deno Deploy), it will use it and if not, it will fallback to the polyfill.

@BrunoBernardino I'll check out fly.io. I've looked at Cloudflare Workers as an alternative, but I ran into issues immediately trying to follow the instructions at https://deno.land/manual@v1.28.1/advanced/deploying_deno/cloudflare_workers. I have used AWS Lambda extensively for the past 5+ years and I have tried https://github.com/hayd/deno-lambda, but one of the biggest draws of Deno Deploy is the zero-config, and AWS is so much config. It looks like Google Cloud Run is another option and Digital Ocean and AWS LightSail for running Deno inside of Docker. Do people have any other recommendations that are closer to the Deno Deploy DX? I assume Vercel can run Deno and it has a similar DX.

@ry and Deno team, any plans to allow dynamic imports in Deno Deploy?

@gnestor
Copy link

gnestor commented Dec 11, 2022

It looks like dynamic imports will also fail in Vercel but they have a workaround: https://github.com/vercel-community/deno#dynamic-imports

Dynamic Imports

By default, dynamic imports (using the import() function during runtime) will fail. For most use-cases, this is fine since this feature is only necessary for rare use-cases.

However, when dynamic imports are required for your endpoint, the DENO_DIR environment variable will need to be set to "/tmp". This is required because the file system is read-only, within the Serverless Function runtime environment, except for the "/tmp" dir. Because dynamic imports will require compilation at runtime, the deno cache directory needs to be writable.

Is this workaround possible with Deno Deploy?

mariofdezzz added a commit to mariofdezzz/dinoapi that referenced this issue Jan 13, 2023
@rawkakani
Copy link

Any movement on this? It's keeping me from using Deno Deploy for a project

Edit: I came up with a workaround; I'll share it here for others that may be stuck.

My situation is one where I didn't strictly need dynamic imports (the modules to be imported all exist in source control), I just wanted to import them dynamically for ergonomics; when I add a new file in a certain directory, I want it to be picked up without going and manually configuring it to be loaded.

What I did as a workaround is I wrote a script to walk that directory and generate a TypeScript file that statically imports all the relevant modules, and re-exports their contents in a way where they can be looked up by module path. This manifest is then checked into source control, so by the time it gets to Deno Deploy everything is static. Hopefully I'll be able to drop this mechanism one day.

You can see it here: https://github.com/brundonsmith/site/blob/master/routes-manifest-generate.ts

I really wanted to avoid this, what happened to no build step, one of Deno original selling point

derkoe added a commit to derkoe/qwik-todos that referenced this issue May 4, 2023
derkoe added a commit to derkoe/qwik-todos that referenced this issue May 4, 2023
@TheYuriG
Copy link

Goddamnit, there should really be some kind of warning about this when using it in development, even if it's just some CLI warning, Deno already does a great job constantly warning us to not perform anti-patterns. This should be definitely added to avoid us developers wasting so much time developing a feature that will not work on Deno Deploy (if you guys want it to be the defacto choice for Deno websites, that is), but will work just fine everywhere else (like the user above mentioned using Digital Ocean).

I did a whole thing where I created blog posts and would dynamically load them from [blog]/[post].tsx and now I'll need to create a bunch of individual .tsx files instead of just being able to dynamically use them that way.

I love the DX, but I'll be damned if the overall (lack of|outdated) documentation doesn't put a damper on my excitement about this runtime.

@BrunoBernardino
Copy link

BrunoBernardino commented May 24, 2023

Goddamnit, there should really be some kind of warning about this when using it in development, even if it's just some CLI warning, Deno already does a great job constantly warning us to not perform anti-patterns. This should be definitely added to avoid us developers wasting so much time developing a feature that will not work on Deno Deploy (if you guys want it to be the defacto choice for Deno websites, that is), but will work just fine everywhere else (like the user above mentioned using Digital Ocean).

I did a whole thing where I created blog posts and would dynamically load them from [blog]/[post].tsx and now I'll need to create a bunch of individual .tsx files instead of just being able to dynamically use them that way.

I love the DX, but I'll be damned if the overall (lack of|outdated) documentation doesn't put a damper on my excitement about this runtime.

Tell me about it. Compare https://github.com/BrunoBernardino/deno-boilerplate-simple-website/blob/main/routes.ts#L43-L44 (what's needed if Deno Deploy supported it):

// NOTE: Use this instead once https://github.com/denoland/deploy_feedback/issues/1 is closed
// const { pageContent } = await import(`./pages/${id}.ts`);

vs https://github.com/BrunoBernardino/deno-boilerplate-simple-website/blob/main/routes.ts#L10-L24 (what's necessary for it to work on Deno Deploy):

// NOTE: This won't be necessary once https://github.com/denoland/deploy_feedback/issues/1 is closed
import * as indexPage from './pages/index.ts';
import * as ssrPage from './pages/ssr.ts';
import * as dynamicPage from './pages/dynamic.ts';
import * as formPage from './pages/form.ts';
import * as webComponentPage from './pages/web-component.ts';
import * as reactPage from './pages/react.tsx';
const pages = {
  index: indexPage,
  ssr: ssrPage,
  dynamic: dynamicPage,
  form: formPage,
  webComponent: webComponentPage,
  react: reactPage,
};

@cowboyd
Copy link

cowboyd commented Jun 7, 2023

This is a show stopper for using MDX on Deno Deploy without introducing a build step, which is a shame.

@yuhr
Copy link

yuhr commented Jun 7, 2023

What I was surprised at is that Fresh states it has “No build step”, but actually it does a build internally. It's just hidden behind some UX design while development, but if one wants to track the project by Git (necessarily!), they has to be aware of this fact, as noticed in the generated fresh.gen.ts:

// DO NOT EDIT. This file is generated by fresh.
// This file SHOULD be checked into source version control.
// This file is automatically updated during development when running `dev.ts`.

It's okay for me, but feels like this could introduce chances of deployment failure, like forgetting to regenerate fresh.gen.ts when adding/removing new routes. Hopefully I would like to see Deno Deploy supports dynamic imports. Any kind of filesystem-based routing framework would be happy with it.

cowboyd added a commit to thefrontside/effection that referenced this issue Jun 22, 2023
As part of the migration to v3 we need to be able to update the
documentation as well be able to have a method to embed playgrounds
into our websites. This will be crucial for Effection, but
also in derivative libraries and future products.

Goals:

1. Fast deploys, easy previews.
2. Zero build
3. Just HTML™️
4. Explicit vs Implicit Render

This is just simple Deno server that serves HTML templates. The server
definition is in `www/server.ts`. It uses a route recognizer to parse
path and query parameters, and then calls an HTML template that is
expressed in JavaScript (The data structure is
defined by https://github.com/cowboyd/html) and then serialized to a
DOM using [deno_dom](https://github.com/denoland/deno_dom) and
Google's [incremental-dom`
library](https://github.com/google/incremental-dom).

Tailwind CSS is used as the atomic CSS framework.

The documentation, like the v2 website is based on MDX. Ideally, we
would like to not require a build step for this, and in development
mode we can, by compiling the MDX into a JavaScript module. However,
becaue Deno Deploy [does not support dynamic
import](denoland/deploy_feedback#1), this is
not an option at the moment.

Future directions:

- I think we can simplify things considerably by
using [hast](https://github.com/syntax-tree/hastscript) as the
structural representation of the HTML. This means several things: We
can apply rehypejs plugins at any level, not just MDX, and also we do
not need to use `deno_dom` nor `incremental-dom` for server side
rendering since there is a direct transform from `hast` -> `string`

- It would be nice to have autocompletion and type checking for
tailwind classes.

- Because we're based on Effection, we can use really nice helpers to
interrupt a request mid-flight to redirect, render 404, etc...
cowboyd added a commit to thefrontside/effection that referenced this issue Jun 22, 2023
As part of the migration to v3 we need to be able to update the
documentation as well be able to have a method to embed playgrounds
into our websites. This will be crucial for Effection, but
also in derivative libraries and future products.

Goals:

1. Fast deploys, easy previews.
2. Zero build
3. Just HTML™️
4. Explicit vs Implicit Render

This is just simple Deno server that serves HTML templates. The server
definition is in `www/server.ts`. It uses a route recognizer to parse
path and query parameters, and then calls an HTML template that is
expressed in JavaScript (The data structure is
defined by https://github.com/cowboyd/html) and then serialized to a
DOM using [deno_dom](https://github.com/denoland/deno_dom) and
Google's [incremental-dom`
library](https://github.com/google/incremental-dom).

Tailwind CSS is used as the atomic CSS framework.

The documentation, like the v2 website is based on MDX. Ideally, we
would like to not require a build step for this, and in development
mode we can, by compiling the MDX into a JavaScript module. However,
becaue Deno Deploy [does not support dynamic
import](denoland/deploy_feedback#1), this is
not an option at the moment.

Future directions:

- I think we can simplify things considerably by
using [hast](https://github.com/syntax-tree/hastscript) as the
structural representation of the HTML. This means several things: We
can apply rehypejs plugins at any level, not just MDX, and also we do
not need to use `deno_dom` nor `incremental-dom` for server side
rendering since there is a direct transform from `hast` -> `string`

- It would be nice to have autocompletion and type checking for
tailwind classes.

- Because we're based on Effection, we can use really nice helpers to
interrupt a request mid-flight to redirect, render 404, etc...
@ry
Copy link
Member

ry commented Jul 11, 2023

This is now supported https://deno.com/deploy/changelog#statically-analyzable-dynamic-imports

@ry ry closed this as completed Jul 11, 2023
@Industrial
Copy link

This is a great feature! Now the sky is the limit =)

@ceifa
Copy link

ceifa commented Jul 11, 2023

Actually only statically analyzable doesn't solve my use case :/

@TheYuriG
Copy link

This doesn't help my use case either. If the issue is considered complete now, I'm glad that I've pivoted to another method of fetching my files, but it would have sucked if I had waited for this.

@cowboyd
Copy link

cowboyd commented Jul 12, 2023

This is a show stopper for using MDX on Deno Deploy without introducing a build step, which is a shame.

It turn's out I was wrong here. You can use MDX without a build step on deno deploy. For any other MDX users who come across this, it supports an evaluate() method which will compile the MDX dynamically and eval() it. (eval caveats apply!)

You can't do static imports inside your MDX, but you can just do static imports inside your JS code and then pass those values down into the mdx scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests