eta icon indicating copy to clipboard operation
eta copied to clipboard

Deno Deploy: Deno.lstatSync is not a function

Open sejori opened this issue 3 years ago • 1 comments

Describe the bug Eta is currently unusable on Deno Deploy because it uses Deno.existsSync which uses Deno.lstatSyncunderneath which is not currently supported by Deploy.

To Reproduce Deploy any script that imports and uses the renderFile eta method to Deno Deploy

Logs

TypeError: Deno.lstatSync is not a function at existsSync (https://deno.land/[email protected]/fs/exists.ts:19:14) 
  at searchViews (https://deno.land/x/[email protected]/file-utils.ts:80:17) 
  at getPath (https://deno.land/x/[email protected]/file-utils.ts:115:27) 
  at renderFile (https://deno.land/x/[email protected]/file-handlers.ts:155:29)

Package & Environment Details

  • Environment: Deno Deploy (deployctl)
  • Version: 1.1.0

sejori avatar May 12 '22 17:05 sejori

I think the fix is to swap out the synchronous fs imports in file-utils.ts and file-methods.ts for their asynchronous counterparts (and probs worth updating to a more recent fs version while in there). This may require quite a large refactor to support Promises however.

sejori avatar May 12 '22 17:05 sejori

Here is a temporary fix that allows you to at least use templates on Deno Deploy :)

Eta.config.includeFile = function(path, data) {
  return Eta.templates.get(path)(data, Eta.config);
};

I would then write something like this:

Eta.templates.define("main", Eta.compile(
    await Deno.readTextFile(`${Deno.cwd()}/views/main.eta`)));

const template = await Eta.render(await Deno.readTextFile(`${Deno.cwd()}/views/home.eta`), {
    title: "My webpage"
});

And this in the templates:

// home.eta

<% layout("main") %>

<h1>Welcome to my home page</h1>
// main.eta

<!DOCTYPE html>
<html lang="en">
<head>
    <title><%= it.title %></title>
</head>
<body>
    <%~ it.body %>
</body>
</html>

christian-dale avatar Jan 14 '23 17:01 christian-dale

@sebringrose thanks for reporting on this issue.

I think the fix is to swap out the synchronous fs imports in file-utils.ts and file-methods.ts for their asynchronous counterparts (and probs worth updating to a more recent fs version while in there). This may require quite a large refactor to support Promises however.

This is correct. Luckily, we're working on the next version of Eta, which will include refactored and fully asynchronous file handling :)

@christian-dale thanks for contributing a temporary fix!

bgub avatar Jan 21 '23 04:01 bgub

I am encountering the same error, and also using the above Deno.readTextFile() doesn’t work in the context of Supabase Edge Functions, so I’m stuck currently.

Eta seem to be the best option for server-side templates, which I try to use for compiling and sending emails. Happy to help with diagnosing, testing, triaging, etc.

matthewmorek avatar Feb 11 '23 14:02 matthewmorek

@matthewmorek I haven't been able to think of a way to fix this in version 2, so it will probably have to wait until version 3.

But, I think you should be able to use @christian-dale's solution by modifying it slightly to use readFile.

const decoder = new TextDecoder("utf-8");
const template = await Deno.readFile(`${Deno.cwd()}/views/main.eta`);
Eta.templates.define("main", Eta.compile(decoder.decode(template)));

bgub avatar Feb 14 '23 00:02 bgub

@nebrelbug It works well locally, however the particular deployment env I'm using (Supabase) doesn't allow read/write to FS, so the workaround is to use an ESM template literal via import, then process it as you would any other string.

matthewmorek avatar Feb 14 '23 07:02 matthewmorek

Great workaround!

bgub avatar Feb 14 '23 18:02 bgub

@matthewmorek I haven't been able to think of a way to fix this in version 2, so it will probably have to wait until version 3.

But, I think you should be able to use @christian-dale's solution by modifying it slightly to use readFile.

const decoder = new TextDecoder("utf-8");
const template = await Deno.readFile(`${Deno.cwd()}/views/main.eta`);
Eta.templates.define("main", decoder.decode(template));

Hello, I'm facing the same issue and I'm a bit lost.

I have this code:

const html = await renderFile(`/base.eta`, {
    title: attrs.title,
    content: markup,
    links: { postLink: outputFilename },
  });

what is expected to do here?

This is my deps.ts

export { extract } from "https://deno.land/[email protected]/front_matter/any.ts";
export { renderMarkdown } from "https://deno.land/x/[email protected]/mod.ts";
export {
  renderFile,
  configure,
  templates,
} from "https://deno.land/x/[email protected]/mod.ts";

I added this 2 lines

const template = await Deno.readFile(`${templatesDir}/base.eta`);

templates.define("base", decoder.decode(template));

but I get this error:

Argument of type 'string' is not assignable to parameter of type 'TemplateFunction'.deno-ts(2345)

I know this is a newbie question, but this is what I am :)

sebazelonka avatar Mar 28 '23 20:03 sebazelonka

@sebazelonka sorry, there was a typo in my previous comment. You'd have to write Eta.templates.define("main", Eta.compile(decoder.decode(template)));

I can't check this right now, but will you let me know if this works?

const template = await Deno.readFile(`${templatesDir}/base.eta`);

Eta.templates.define("base.eta", Eta.compile(decoder.decode(template)));

Eta.configure({cache: true});

let res = await Eta.renderFile(`base.eta`, {
    title: attrs.title,
    content: markup,
    links: { postLink: outputFilename },
  });

bgub avatar Apr 01 '23 19:04 bgub

For all those using Deno Deploy, they just added support for Node.js built-ins like fs. I believe file handling should now work! Can anyone confirm that for me?

bgub avatar May 29 '23 14:05 bgub

I've just tested and can confirm that eta.renderFile is functional with the latest versions of Deno Deploy. :tada: :tada:

bgub avatar Jun 03 '23 22:06 bgub