DEV Community

Benny Powers ๐Ÿ‡ฎ๐Ÿ‡ฑ๐Ÿ‡จ๐Ÿ‡ฆ
Benny Powers ๐Ÿ‡ฎ๐Ÿ‡ฑ๐Ÿ‡จ๐Ÿ‡ฆ

Posted on • Originally published at bennypowers.dev on

Typescript Eleventy Config

There are a bunch of guides out there explaining how to write 11ty configs in typescript so that you can compile them prior to running 11ty. This isn't one of those. I'm here to explain how to run eleventy on your typescript configs, with all the familiar editor ergonomics, without building your config files at all. Dev time, meet runtime.

You'll need node.js 22.6 or later, which adds the --experimental-strip-types flag. What this does is tell node to just ignore typescript syntax, as if it was a comment. Node here is basically implementing the types as comments proposal, and I hope everyone else follows suit quickly.

Doing the Cool Kids' Homework

Now, 11ty follows the types-in-jsdoc approach, which is fine i guess whatever, but for some reason, they don't then ship those types in .d.ts files, so we'll have to build them ourselves. Run this script in postinstall:

import { $ } from 'execa';

import Manifest from '../package.json' with { type: 'json' };

await $`npx tsc node_modules/@11ty/eleventy/src/UserConfig.js
        --declaration
        --allowJs
        --emitDeclarationOnly
        --moduleResolution nodenext
        --module nodenext
        --target esnext`;

for (const pkg in Manifest.dependencies) {
  if (pkg.startsWith('@11ty')) {
    const spec = import.meta.resolve(pkg).replace('file://', '');
    try {
      await $`npx tsc ${spec}
              --declaration
              --allowJs
              --emitDeclarationOnly
              --moduleResolution nodenext
              --module nodenext
              --target esnext`;
    } catch(e) {
      console.log(e.stdout);
    }
    console.log(`Wrote types for ${pkg}`)
  }
}
Enter fullscreen mode Exit fullscreen mode

Shipping .d.ts type declarations in your npm library is an accessibility issue. Your users with cognitive disabilities like ADHD can't afford to keep alt-tabbing back to your docs site. I hope the 11ty authors will integrate this into their build system soon.

TypeScript, Ho!

That having been accomplished, rename your config file and import the UserConfig type:

mv eleventy.config.js eleventy.config.ts
Enter fullscreen mode Exit fullscreen mode
import type { UserConfig } from '@11ty/eleventy';

export default function(eleventyConfig: UserConfig) {
  eleventyConfig.
}
Enter fullscreen mode Exit fullscreen mode

And watch those LSP-completion suggestions roll in.

If you have split your config into multiple files, you need to enable .ts extension in your tsconfig.json. Also disable emit, because we're not actually running tsc at any point, this is all for neovim.

Here, crib mine:

{
  "compilerOptions": {
    "module": "NodeNext",
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true,
    "moduleResolution": "NodeNext",
    "allowImportingTsExtensions": true,
    "target": "ESNext",
    "noEmit": true
  }
}
Enter fullscreen mode Exit fullscreen mode

Last thing is to actually run it, and to do that we'll use the NODE_OPTIONS environment variable

"scripts": {
  "build": "NODE_OPTIONS='--experimental-strip-types' eleventy --config=eleventy.config.ts --incremental",
  "start": "NODE_OPTIONS='--experimental-strip-types' eleventy --config=eleventy.config.ts --serve --incremental"
},
Enter fullscreen mode Exit fullscreen mode

Gimmie the Code

And that's pretty much it! I accomplished the above on this site in commit 307e5cf8, which you're welcome to ogle over at Microsoft's loss-leader code scraping utility.

Top comments (0)