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

How to use TypeScript with Eleventy? #577

Closed
d2s opened this issue Jun 19, 2019 · 44 comments
Closed

How to use TypeScript with Eleventy? #577

d2s opened this issue Jun 19, 2019 · 44 comments
Labels
enhancement typescript Type definitions and Typescript issues

Comments

@d2s
Copy link
Contributor

d2s commented Jun 19, 2019

Are there examples of how to use TypeScript with Eleventy?

Would like to be able to use TS with 11ty.

@Ryuno-Ki
Copy link
Contributor

Have you tried it yourself, yet?
If so, where did you get stuck?
(I'm not a fan of TypeScript, personally).

@hdoro
Copy link

hdoro commented Jun 21, 2019

As far as I understand, the only current way to do so is through using the --watch flag that will transpile the code whenever there's a change; eleventy then picks up on these changes through its own --watch and rebuilds corresponding part of the website.

In theory, this works fine, but it presents a huge burden on our workload, as you now have to wait for 2 processes to happen in sequence before you can see any change propagate. I've recently gotten into the same situation when trying to use Svelte as a template engine for specific parts of my site, and would love to know if there's any specific implementation that mitigates this problem.

My current implementation is as follow:

  1. Have Rollup bundle my Svelte app with a Server (SSR) and a Client (with hydration) configuration;
  2. Set it to watch changes to my Svelte directory, which triggers a new Rollup build;
  3. Then inside my .11ty.js template I import the Server.js bundle, run the SvelteApp.render() method that return an html string, which I then return in the Eleventy layout;
  4. For client-side hydration, I also include a <script src="svelteApp.js" defer> that refers to the client bundle generated by Rollup;
  5. This client bundle is generated inside a mid-way dist folder that Eleventy then picks up through addPassthroughCopy;
  6. Finally, I run eleventy --serve and hope for the best.

Problems:

  • Every little change has to go through Rollup and Eleventy. This is not a problem with a small codebase like the one I'm fiddling with, but it could become one for full-blown projects;
  • For some strange reason, .11ty.js templates don't update until I run eleventy --serve again, even though Eleventy does notice a change and rebuilds the website, very odd behavior. This makes testing the SSR impossible while developing, as changes to the Server.js don't get reflected in the browser;
  • And, most importantly, the above problem would suck for developing Typescript .11ty.ts templates, as they simply wouldn't change. Worth the shot, though!

NOTE: I know this is not related directly to Typescript, but as I'm dealing with transpilation much like you'd with TS, this might be of help. If needed, I can transfer the svelte discussion somewhere else 🤗

@jevets
Copy link

jevets commented Jun 21, 2019

Hmm, stabbing in the dark here, but a few things that might stoke the fire:

  • eleventy --watch: bring your own dev server and Eleventy will rebuild to eleventyConfig.dir.output

  • Another thing to consider: put all your .ts files into _includes; Eleventy will automatically watch all files in _includes and rebuild. Not ideal. (I end up sometimes putting static files into _includes just for the sake of triggering a rebuild when running eleventy --serve|watch)

  • Maybe take advantage of the new(ish) JS dependencies watch config flag. Maybe there's a way you could generate a file that require()s your typescript files somehow, which could instruct Eleventy to spider into your .ts files, thereby buying you free watching.

  • Or you could even require them from .eleventy.js and not even consume them, again simply to trigger rebuilds and free watch.

  • Even more food for thought: Eleventy can write template files into _includes and avoid writing them to eleventyConfig.dir.output, which has its (albeit sparse) uses.


For some strange reason, .11ty.js templates don't update until I run eleventy --serve again...

That's odd, I haven't noticed this. Maybe I experience the same and simply haven't noticed, or maybe there's something else going on.

@Ryuno-Ki
Copy link
Contributor

I end up sometimes putting static files into _includes

I symlinked some :-)

@jevets
Copy link

jevets commented Jun 21, 2019

@Ryuno-Ki good call!

Ultimately, it'll be much easier handling .ts when #117 comes up

@zachleat
Copy link
Member

Wow #117 has 53 upvotes!

@zachleat
Copy link
Member

I would definitely say this is dependent on #117 but I’ll go ahead and put this into the enhancement queue since it’s kind of a standalone thing.

@zachleat zachleat added enhancement needs-votes A feature request on the backlog that needs upvotes or downvotes. Remove this label when resolved. labels Jun 22, 2019
@zachleat
Copy link
Member

This repository is now using lodash style issue management for enhancements. This means enhancement issues will now be closed instead of leaving them open.

View the enhancement backlog here. Don’t forget to upvote the top comment with 👍!

@hdoro
Copy link

hdoro commented Jul 4, 2019

@jevets Thanks for the thought process, I ended up settling for parallel Rollup and PostCSS processes that paste files in a folder that Eleventy picks up with pass-through copy. It's working nicely, but the 11ty.js updating problem is still a reality, I even filed an issue on this #596 😔

Would be amazing if you could try reproducing it o/

@chriskrycho
Copy link

chriskrycho commented Nov 18, 2019

In addition to the other tweaks with --watch suggested above, I found that using ts-node and just registering it at the top of the .eleventy.js file works quite nicely.

Alas, it does not trigger rebuilds for changes to the config (I think that's expected?), but it does build everything correctly… and you can use one small hack to be able to watch for changes to .ts files in the main app area without needing to drive it through a separate watcher. Instead of making a .11ty.js file which has all the implementation, have a .11ty.ts file which the .11ty.js file imports and then simply re-exports.

(That blog post will probably be late this week or sometime next week; feel free to just poke at the source in the meantime. It includes type defs for most of the API surface of Eleventy! I plan to get those on DefinitelyTyped by the end of the year.)

@spacedentist
Copy link

I plan to get those on DefinitelyTyped by the end of the year.

That would be much much appreciated, @chriskrycho !

@chriskrycho
Copy link

I’ll see if I can get them up. Just as I’m moving off of 11ty to my own thing! (Not 11ty’s fault. Just finally getting a handle on doing exactly what I’ve wanted to for half a decade!)

@Ryuno-Ki
Copy link
Contributor

As I get more experience with using JSDoc annotations for typechecking using tsc, I can use TypeScript for serving some type annotations.
That could lead to a .d.ts file for type checks (and the rest of the code base in .js).
Would that be something worthwhile for everyone?

@paulshryock
Copy link
Contributor

Hey @Ryuno-Ki is there any update on including a type declaration file, so TypeScript users can import Eleventy from @11ty/eleventy without getting error TS7016: Could not find a declaration file for module '@11ty/eleventy'.?

@chriskrycho
Copy link

chriskrycho commented Jan 8, 2022

Do feel free to steal from mine, which are still mostly accurate but now a bit out of date. (I haven’t switched off of 11ty, but I also haven’t had time to publish those in any way, and likely won’t—just not at or anywhere near the top of my priority list).

(I'm unsubscribing from this, so won't see further conversation in general.)

@paulshryock
Copy link
Contributor

paulshryock commented Jan 9, 2022

Hmm, I tried saving that file as types/eleventy.d.ts in my project, but it didn't work. I've tried 100 different TypeScript configuration settings, still doesn't work. 🤷 I ended up replacing that with declare module '@11ty/eleventy', which should work like a sledgehammer, but still doesn't.

Not that I expect anyone to look at my code, but here's my current setup, if anyone has 2 minutes to look it over for something I might be missing. My Eleventy build code is in /bin/build.ts. Runs on npm start; requires Node 17.

@chriskrycho
Copy link

@paulshryock without looking at your project, take a look at the tsconfig.json and my .eleventy.js files in my project as well. The former will make types resolve correctly; the latter just imports a bunch of TS files to author in (specifically one major file for the actual config) and runs them using ts-node. The root file itself wasn’t able to be authored in TS when I built that type definition, so I had the .eleventy.js just use the TS files.

@paulshryock
Copy link
Contributor

Yeah I checked out those files. I'm already using ts-node in my CLI build script like node --es-module-specifier-resolution=node --loader ts-node/esm bin/build.ts, but I'll play around with it some more. I might end up just using Eleventy via CLI--not the end of the world, but was hoping to use the new Programmatic API from v1.0.0. Thanks!

@jahilldev
Copy link

jahilldev commented Feb 3, 2022

I was in need of this very setup, after some trial and error I got it all working pretty nicely. TypeScript doesn't necessarily have to be supported by 11ty for people to make use of it.

I wrote a very short article on how I went about it below:
https://www.jameshill.dev/articles/typescript-and-11ty/

There's also a fully kitted out starter that I mention in the article:
https://github.com/jahilldev/11tyby

@paulshryock
Copy link
Contributor

Nice writeup @jhukdev!

For my use case I'm importing 11ty programmatically, and that's where the missing type information becomes a problem.

import Eleventy from '@11ty/eleventy'

(async function() {
  const elev = new Eleventy()
  await elev.write()
})()

@notjosh
Copy link

notjosh commented Feb 13, 2022

fwiw I've had success using esbuild-runner to run the project (mostly) out of the box. You'll probably need to use the --cache argument to get parsing working properly in templates.

I use this patch-package with this patch to add TypeScript file extension awareness to 11ty (and force some cache invalidation, so esbuild-runner can play nicely.)

Then you can invoke 11ty with: yarn esr --cache ./node_modules/.bin/eleventy --config ./.eleventy.ts [command...] (I wrapped it in an alias, so it's transparent for me).

@manunamz
Copy link

manunamz commented Feb 24, 2022

Here is an 11ty template in typescript in case anyone needs it (I didn't see it in any of the links in this thread -- though I might have missed it):

https://github.com/c0derabbit/eleventy-starter-typescript

@zachleat
Copy link
Member

I did want to reference this one too using the new addExtension API

https://twitter.com/zachleat/status/1473036576468918279

@jahilldev
Copy link

@zachleat Ahh this is an interesting solution! I hadn't considered this approach, thanks! 👍

@pspeter3
Copy link

You all may be interested in #2279 which was the smallest patch that was able to get @notjosh's solution to work. It does require running Eleventy with a transpiler like esbuild-runner, esbuild-register, or ts-node but it just works from there.

@panoply
Copy link

panoply commented May 15, 2022

This was bugging me so I shipped a drop-in solution. I was able to get a fair bit covered. Methods are JSDoc annotated with relative links to online documentation on the 11ty website. There is no support for plugin types, ie: eleventyConfig.addPlugin(somePlugin, {}) will not give you anything. There is not much that can really be done about that without manually typing them and relying on something like typeof for comparison. This due to the way plugins are consumed by Eleventy.

In any sense, these configuration supported typings should help in productivity.

Install

Surprisingly 11ty was not taken on the registry. Given this solution is geared towards the project as a whole, it can be consumed as such. Keep in mind the @11ty/eleventy is a peer and you need to install it too.

As per #577 (comment) the module can be consumed using @panoply/11ty

pnpm add @panoply/11ty

https://github.com/panoply/11ty

Live Example

Screen.Recording.2022-05-15.at.06.55.43.mov

@paulshryock
Copy link
Contributor

paulshryock commented May 16, 2022

This was bugging me so I shipped a drop-in solution. I was able to get a fair bit covered. Methods are JSDoc annotated with relative links to online documentation on the 11ty website... these configuration supported typings should help in productivity.

Thanks @panoply! Any work towards getting types for Eleventy is much appreciated, and I'm sure many people will find this useful.

Surprisingly 11ty was not taken on the registry. Given this solution is geared towards the project as a whole, it can be consumed as such. Keep in mind the @11ty/eleventy is a peer and you need to install it too.

Why wouldn't typings just be included in Eleventy core via a pull request, or added to a potential @types/11ty package via https://github.com/DefinitelyTyped/DefinitelyTyped?

Having some types for just the eleventy config object in a 3rd-party repo maintained by 1 person, using the global package name 11ty seems like not the right way to go. And is potentially typo-squatting. Many people will npm install 11ty without realizing that they're not installing Eleventy core directly. This seems like a potential security vulnerability down the road. cc: @zachleat

@panoply I'm not against having your own personal wrapper for any project, but couldn't it be namespaced like @panoply/11ty?


Edit: Instead of "And is potentially typo-squatting", I should have said something like "And could have the unintended result of becoming a typo-squatting vulnerability". I didn't mean to directly or indirectly imply any malicious activity from @panopoly. Forgive me for coming off a little too harsh in my above comment.

@panoply
Copy link

panoply commented May 16, 2022

Why wouldn't typings just be included in Eleventy core via a pull request, or added to a potential @types/11ty package via https://github.com/DefinitelyTyped/DefinitelyTyped?

When leveraging an .eleventy.js file the export expects a function, eg: module.exports = function(eleventyConfig) {}. Making a PR on DefinitelyTyped (though I'd be happy to PR there) it would not solve this issue in an elegant manner as the user would still need to annotate with JSDocs, eg: @type {import('..')} and as such, the issue at hand persists. The wrapper eliminates that extra step and having scoured the issues it seems folks have had trouble understanding how JS Doc annotated types. There is also the aspect of editors, as JSDocs annotated types are a feature of the TypeScript LS. Some editors (AFAIK) do not employ the TS language server and handle such logic differently.

Types are assumed and should not require JSDoc comment annotations, hence the wrapper. The same logic is employed with other projects, for example in Rollup you can import defineConfig to pull in type completions within the rollup.config.js file. It is probably important to note that some consideration was taken here and it goes beyond configuration types, but also my hopes is that an approach can be establish for type completion in 11ty plugins. As it stands, Eleventy digests plugins from the method addPlugin(plugin, opts) and as such this makes it a little difficult to pass completions.

Having some types for just the eleventy config object in a 3rd-party repo maintained by 1 person, using the global package name 11ty seems like not the right way to go.

Agreed. It is important to note that given the module is directly focused for 11ty the thought process is completely targeted towards the project users. In addition, the module has a peer on (@11ty/eleventy) but in saying that, I'd be more than happy to relinquish ownership of the registry name and pass it to 11ty and your core team. I don't want to rustle any feathers here and it seems I am doing just that.

I'm not against having your own personal wrapper for any project, but couldn't it be namespaced like @panoply/11ty?

Again, I'd be happy to pass it over. My intentions are anything but "typo-squatting" and far more focused on actionable steps to bring type support into Eleventy. This issue per-say has seen no traction and it is rather difficult to get PR's merged or considered.

@panoply
Copy link

panoply commented May 16, 2022

Registry name 11ty was removed as per #577 (comment) and instead can be consumed via @panoply/11ty - Might be worth getting it under the org sooner rather than later @paulshryock

@paulshryock
Copy link
Contributor

paulshryock commented May 16, 2022

@panoply, I apologize if it seemed like my feathers were rustled or if I was telling you what to do. I have no affiliation with Eleventy (I'm just a user), and was just trying to voice concerns for further discussion. I hear what you're saying about the technical implementation--how your approach as-is seems to work better for now as a module wrapper. Your explanation was helpful.

My intentions are ... focused on actionable steps to bring type support into Eleventy.

I think anything that brings us closer to TypeScript support is a good thing, so I just want to reiterate my thanks for your hard work on this--and hopefully assure you that I wasn't trying to call you out or accuse you of doing anything wrong. (Reading back over my initial comment; it may have sounded harsher than I meant--sorry!)

This issue per-say has seen no traction and it is rather difficult to get PR's merged or considered.

I wasn't aware of this--did you try opening a PR to add the relevant type declarations in this repo?

@panoply
Copy link

panoply commented May 16, 2022

@paulshryock No apologies needed, I didn't think you were calling me out, but hearing how you voiced your concerns, I didn't want folks to think I had malicious intent or anything like this.

My thoughts in using the 11ty name were because the module is literally a single line of code, eg: module.exports = cb => cb and it requires eleventy's core as a peer. I could of gone as far as printing a disclaimer on postinstall - it felt fitting (to me) that is just me. Either way, I removed the registry name and instead did as you recommended.

I wasn't aware of this--did you try opening a PR to add the relevant type declarations in this repo?

So 11ty is somewhat known for this and personally, I do not consider it a bad thing, I mean the less contributions sometimes the better the code. Look at the success of esbuild and how Evan approaches his project, so I wouldn't want to bother core maintainers with something a frivolous as this. Previous discussions and issues relating to this have pretty much died out or gone stale.

Though I could PR it wouldn't be fast tracked and folks in the past have made somewhat similar PR's or opened dialogue but nothing has come fruition.

Shipping this as wrapper module allows users to simply pnpm add 11ty pnpm add @panoply/11ty, pass it to module.exports and Eleventys types will be at their fingertips. Because the module is mostly a declaration, PRs would be fast and much easier to wrangle because its a tiny 3rd-party repo maintained by 1 person.

@d2s
Copy link
Contributor Author

d2s commented May 16, 2022

Eventually it would be a good thing to have either TypeScript types and improved JSDoc annotations as part of Eleventy itself. Understandably popularity of Eleventy has grown a lot over the years, as the project slowly changed from a personal project of Zack to something more. Still, almost all of the code changes are made by him, so any major changes would need agreement from Zack.

Problem with 3rd party types is that those often get outdated quite fast, even for projects with a reasonably low amount of changes. Question is also about who is the target audience.

Even while the weekly downloads of @11ty/eleventy https://www.npmjs.com/package/@11ty/eleventy package are around ~37-43K downloads, it is still a limited how many of those users are making more advanced customizations of Eleventy itself. Having better types would improve developer experience for part of people, but would require reasonable amount of effort to keep updated.

When looking at https://github.com/11ty/eleventy/graphs/contributors statistics, it shows that there are ~70 contributors in total, and most of those are with ~1-4 commits in total (per person). Situation would be a bit different if there would be multiple active contributors to the main Eleventy codebase. Extensions have variety of contributors, but what matters here most is how main codebase is developed. We can't make any decisions on behalf of Zach. But we can ask for his opinions about the future directions of Eleventy. Understandably he has a bit more time & focus for the overall project at the moment, so it would be interesting to see where this goes in the future.

2022-05-16 22 02 06 github com 5cc06723f8ca - Contributors to 11ty_eleventy

@panoply
Copy link

panoply commented May 16, 2022

@d2s Given the current architecture shipping types without needing to reach for JSDocs annotations can only be realistically achieved by passing module.exports a function. There is no way of achieving this without a wrapper because the default export is a class:

const Eleventy = require("@11ty/eleventy");

// Create an instance
const eleventy = new Eleventy()

Those developers using the default class export (ie: programmatic control) can indeed benefit from DefinitelyTyped but it will not solve the issue for developers using the .eleventy.js configuration file and I'm going to assume the majority are using the latter based on the plugin ecosystem and the streamlined control for generated site customizations. Given the .eleventy.js configuration file expects a function there is no way types can be asserted without comment annotation:

module.exports = function(eleventyConfig) {}

Currently, folks who are leveraging comment JSDoc annotations need to do this:

/**
 * @type {import('@11ty/eleventy')}
 */
module.exports = function(eleventyConfig) {}

Such an approach is extraneous and not necessarily fluent for a couple of reasons.

  1. A large number of developers are unaware that the TypeScript Language Server supports type checking/completions using JSDocs annotations and thus would never think of using it.
  2. The current typed methods are not mostly incomplete and exist in the core of the codebase. Upkeep is difficult, changes require augmenting source code.
  3. The current approach and discussions pertaining to this are relying on JSDoc typings for said completions/checks. No matter how refined the TS Language Server and compiler is, it needs to generate a virtual declaration (of sorts) to feed the completions/capabilities.

The simplest way to negate JSDoc annotation and also feed Type support is passing a function callback. This is a common practice across multiple projects, it also separates logic and keeps things clean, upkeep is easy and logic is kept separated from the core.

This is to some degree why I went the 11ty registry name. It holds some degree of virtue and would exist as an opt-in that infers relation to the core project. If users want Typings, they can simply install it, pass module.exports the function callback. No need for comment annotations or relying on the TS LS/compiler to generate them from the source. The approach allows the default class export to persist and it does not introduce any breaking changes.

Problem with 3rd party types is that those often get outdated quite fast, even for projects with a reasonably low amount of changes. Question is also about who is the target audience.

I don't necessarily agree here (well to an extent). The methods eleventyConfig exposes is not going to drastically change to a point where third party types would become so outdated that they could not be leveraged. In any sense the TS nexus is vigorously maintained by folks because a lot of developers rely on IntelliSense capabilities. The same argument could be made for DefinitelyTyped typings as a third-party.

I'd argue a third party plugin to be less intimidating for folks to submit a PR opposed to DT. The simple approach here (IMO) is to keep this an opt-in, ship it under the @11ty org and allow the community or core maintainers to monitor its health. This way, the core codebase can exist and no breaking changes are imposed.

Doing this:

const eleventy = require('@panoply/11ty')

module.exports = eleventy(function(eleventyConfig) {

  // etc etc
  
  return {}
})

Lifts the burden from the Eleventy maintainers, they can focus on the JS purity of the project and need not bother about merging or reviewing PR's on core code which are pertaining to types. Anyway, that is just my two cents and if the core team and @zachleat want I'd be happy to assist in maintaining such a module under the org.

@Ryuno-Ki
Copy link
Contributor

Ryuno-Ki commented Jun 4, 2022

Hey @Ryuno-Ki is there any update on including a type declaration file, so TypeScript users can import Eleventy from @11ty/eleventy without getting error TS7016: Could not find a declaration file for module '@11ty/eleventy'.?

No, sorry. Had mental health issues end of last year and then got carried away (in between Covid and everything).

@paulshryock
Copy link
Contributor

No, sorry. Had mental health issues end of last year and then got carried away (in between Covid and everything).

Sorry to hear, and completely understandable -- it's been a hard few years for sure. No worries.

@kvz
Copy link

kvz commented Nov 8, 2022

In case it's helpful to folks stumbling upon this thread, I was not interested in letting TypeScript transpile assets for the end user's browser, as we already use a bundler for that, but I was interested in having Eleventy code itself (config, and all the things (filters, shortcodes, helper functions) it imports, in TypeScript). For this we created a little wrapper .eleventy.js config file with the following contents:

// @ts-check
// This is just a wrapper so we can have our real config in TypeScript.
require('ts-node').register({
  files: true,
  swc: true,
  compilerOptions: {
    module: 'commonjs',
  },
})

// @ts-expect-error to avoid "An import path cannot end with a '.ts' extension. "
const { default: eleventyConfig } = require('./_eleventy/eleventyConfig.ts')

module.exports = eleventyConfig

You'll need at least yarn add --dev @swc/core ts-node typscript for this to work.

From that moment on everything in _eleventy/ is in typescript. Adding swc made it fast, there is no noticeable delay from live-transpiling like this, and not having build steps makes for a nice dx.

I added types by @chriskrycho which were linked higher up this thread and adjusted them a little bit to type the 11ty ts config and to give our code an understanding of what our collections are, etc.

It would certainly be cool if Eleventy at one point could natively load .eleventy.ts if it existed and ts-node happened to be installed. This is how Webpack (via node-interpret) and Jest do it as well, and I don't think it will be as invasive as other ways of supporting TypeScript on the consuming side. Although for us the difference would now just be deleting that 14 LoC JS wrapper file, so it really isn't the end of the world not having that.

I guess a bigger dent would be made if Eleventy provided also support for typescript data files, perhaps via #2279, because this wrapper method gets unwieldy once we start it applying to dozens of files, and eleventyConfig.addDataExtension('ts') can't be used because we don't have the path of the datafile, which will be important to resolve any imports if we want to transpile there.

@panoply
Copy link

panoply commented Nov 9, 2022

@kvz FWIW Leveraging tsup allows for the practically the same thing and uses swc under the hood or better yet joycon is another great alternative.

@kvz
Copy link

kvz commented Nov 16, 2022

JS wrapper file

One more downside of this approach where .eleventy.js requires and transpiles an eleventyConfig.ts, is that changes are no longer picked up by watch. So if you do end up making a config change, you have to restart Eleventy manually in order to see the impact on your build.

I don't think you can manually add more files, such as eleventyConfig.ts, to the watch-list or can you? (google says no)

@kvz
Copy link

kvz commented Nov 21, 2022

I don't think you can manually add more files, such as eleventyConfig.ts, to the watch-list or can you? (google says no)

I was wrong, I found addWatchTarget and it works beautifully 🎉

In eleventyConfig.ts:

// We wrap the eleventy typescript configuration in the original `.eleventy.js` file
// but that means any changes to the eleventy config aren't picked up, unless we add this:
eleventyConfig.addWatchTarget(__dirname)
// ^-- i keep the ts config in an `_eleventy` directory with more files that the config imports, 
// but you may need to change this to `__filename` if it's just a lonely typescript file in the 
// root for instance

@zachleat
Copy link
Member

Wanted to cross post this coming 2.0.0-canary.19 solution from @pspeter3 here https://www.11ty.dev/docs/languages/custom/#aliasing-an-existing-template-language

Relatedly, I have been merging a few types PRs for the Eleventy.js file and configuration files from folks recently into core—appreciate help with those!

@kvz
Copy link

kvz commented Dec 20, 2022

Tried that approach just now to get TS Data Cascade files but for me it ended in:

[11ty] Problem writing Eleventy templates: (more in DEBUG output)
[11ty] You’re trying to use a layout that does not exist: console (undefined) (via Error)
[11ty]
[11ty] Original error stack trace: Error: You’re trying to use a layout that does not exist: console (undefined)
[11ty]     at TemplateLayoutPathResolver.getFullPath (/Users/kvz/code/content/node_modules/@11ty/eleventy/src/TemplateLayoutPathResolver.js:102:13)
[11ty]     at new TemplateLayout (/Users/kvz/code/content/node_modules/@11ty/eleventy/src/TemplateLayout.js:22:7)
[11ty]     at Function.getTemplate (/Users/kvz/code/content/node_modules/@11ty/eleventy/src/TemplateLayout.js:47:18)
[11ty]     at Template.getLayout (/Users/kvz/code/content/node_modules/@11ty/eleventy/src/Template.js:127:37)
[11ty]     at Template.getData (/Users/kvz/code/content/node_modules/@11ty/eleventy/src/Template.js:381:25)
[11ty]     at async TemplateMap.add (/Users/kvz/code/content/node_modules/@11ty/eleventy/src/TemplateMap.js:64:16)
[11ty]     at async Promise.all (index 1785)
[11ty]     at async TemplateWriter._createTemplateMap (/Users/kvz/code/content/node_modules/@11ty/eleventy/src/TemplateWriter.js:257:5)
[11ty]     at async TemplateWriter.generateTemplates (/Users/kvz/code/content/node_modules/@11ty/eleventy/src/TemplateWriter.js:294:5)
[11ty]     at async TemplateWriter.write (/Users/kvz/code/content/node_modules/@11ty/eleventy/src/TemplateWriter.js:341:23)

That's on:

    "@11ty/eleventy": "^2.0.0-canary.20",
    "esbuild": "^0.16.10",
    "esbuild-register": "^3.4.2",
    "typescript": "^4.9.4",

Without the changes suggested by that Gist, it just works, the console layout does exist.

Not sure what the best way to get more details on this error is

@paulshryock
Copy link
Contributor

paulshryock commented Jan 5, 2023

Tried that approach just now to get TS Data Cascade files but for me it ended in:

[11ty] Problem writing Eleventy templates: (more in DEBUG output)
[11ty] You’re trying to use a layout that does not exist: console (undefined) (via Error)

That's on:

    "@11ty/eleventy": "^2.0.0-canary.20",

@kvz, either add a file extension for your template or bump Eleventy to "^2.0.0-canary.21"; that should fix this.

See more info:

@danielrob
Copy link

danielrob commented Mar 11, 2023

My third time looking at this, and finally, a simple end-to-end answer:

If you want:

  • tsx templates
  • a typescript eleventy file
  • eleventy serve to work out of the box - with code changes working correctly, including to the config file itself
  • a really simple solution

Then do this:

  "scripts": {
    "dev": "node --require esbuild-register node_modules/.bin/eleventy --config=.eleventy.ts --serve",
    "build": "node --require esbuild-register node_modules/.bin/eleventy --config=.eleventy.ts"
  },

.eleventy.ts

// must be module.exports, not export defult. 
module.exports = function (eleventyConfig: any) {
  eleventyConfig.addExtension('11ty.tsx', {
    key: '11ty.js',
  });
  
  // dev server doesn't spider js dependencies properly, so opt for hard browsersync with watch. 
  eleventyConfig.setServerOptions({
    module: "@11ty/eleventy-server-browsersync",
    snippet: true,
    watch: true, 
    server: <your output folder>
  });
}

tsconfig.json

{
  "compilerOptions": {
    "jsx": "react" 
    "jsxFactory": "h", 
    "jsxFragmentFactory": "h.Fragment",
  }
}

src/pages/index.11ty.tsx

import h from 'vhtml';

export const data = {
  title: 'Hello world',
};

export function render() {
  return <h1>{data.title}</h1>;
}

run commands:

$ yarn add @11ty/eleventy @11ty/eleventy-server-browsersync esbuild esbuild-register vhtml @types/vhtml
yarn dev

peytondmurray added a commit to peytondmurray/pdmurray.dev that referenced this issue Jul 1, 2023
@zachleat
Copy link
Member

zachleat commented Jun 3, 2024

Official template syntax docs for TypeScript and JSX just shipped here:

https://www.11ty.dev/docs/languages/typescript/
https://www.11ty.dev/docs/languages/jsx/

This also includes an approach to use TypeScript for your Eleventy configuration file too (as contributed by @danielrob above!)

@zachleat zachleat removed the needs-votes A feature request on the backlog that needs upvotes or downvotes. Remove this label when resolved. label Jun 3, 2024
@zachleat zachleat added this to the Eleventy 3.0.0 milestone Jun 3, 2024
@zachleat zachleat added the typescript Type definitions and Typescript issues label Jun 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement typescript Type definitions and Typescript issues
Projects
None yet
Development

No branches or pull requests