Skip to content

How to use TypeScript with Eleventy? #577

Closed

Description

@d2s

Are there examples of how to use TypeScript with Eleventy?

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

Activity

  1. Ryuno-Ki commented on Jun 19, 2019

    @Ryuno-Ki
    Contributor

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

  2. hdoro commented on Jun 21, 2019

    @hdoro

    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 ðŸĪ—

  3. jevets commented on Jun 21, 2019

    @jevets

    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.

  4. Ryuno-Ki commented on Jun 21, 2019

    @Ryuno-Ki
    Contributor

    I end up sometimes putting static files into _includes

    I symlinked some :-)

  5. jevets commented on Jun 21, 2019

    @jevets

    @Ryuno-Ki good call!

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

  6. zachleat commented on Jun 22, 2019

    @zachleat
    Member

    Wow #117 has 53 upvotes!

  7. zachleat commented on Jun 22, 2019

    @zachleat
    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.

  8. zachleat commented on Jun 22, 2019

    @zachleat
    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 👍!

  9. hdoro commented on Jul 4, 2019

    @hdoro

    @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/

  10. chriskrycho commented on Nov 18, 2019

    @chriskrycho

    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.)

  11. spacedentist commented on Dec 24, 2020

    @spacedentist

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

    That would be much much appreciated, @chriskrycho !

  12. chriskrycho commented on Dec 24, 2020

    @chriskrycho

    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!)

  13. 21 remaining items

  14. Ryuno-Ki commented on Jun 4, 2022

    @Ryuno-Ki
    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'.?

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

  15. paulshryock commented on Jun 5, 2022

    @paulshryock
    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.

  16. kvz commented on Nov 8, 2022

    @kvz

    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.

  17. panoply commented on Nov 9, 2022

    @panoply

    @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.

  18. kvz commented on Nov 16, 2022

    @kvz

    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)

  19. kvz commented on Nov 21, 2022

    @kvz

    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
  20. zachleat commented on Dec 14, 2022

    @zachleat
    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!

  21. kvz commented on Dec 20, 2022

    @kvz

    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

  22. paulshryock commented on Jan 5, 2023

    @paulshryock
    Contributor

    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:

  23. danielrob commented on Mar 11, 2023

    @danielrob

    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
    
  24. zachleat commented on Jun 3, 2024

    @zachleat
    Member

    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!)

  25. added this to the Eleventy 3.0.0 milestone on Jun 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions