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

Support TypeScript in Docusaurus config #7911

Closed
2 tasks done
MarkShawn2020 opened this issue Aug 7, 2022 · 7 comments · Fixed by #9317
Closed
2 tasks done

Support TypeScript in Docusaurus config #7911

MarkShawn2020 opened this issue Aug 7, 2022 · 7 comments · Fixed by #9317
Labels
feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future.

Comments

@MarkShawn2020
Copy link
Contributor

MarkShawn2020 commented Aug 7, 2022

Have you read the Contributing Guidelines on issues?

Description

Here I would offer a minimal example on how to create a config file based on typescript and make it run.

Has this been requested on Canny?

No response

Motivation

In TypeScript Support | Docusaurus, it writes that It is not possible to use a TypeScript config file in Docusaurus unless you compile it yourself to JavaScript.

Although JSDoc can be helpful of preventing you make some mistakes about field types, it's not acting well in every places.

Take my own example, I designed an data structure for frontend, and I also need to generate the data from the backend (i.e. customFileds in docusaurus.config.js), then I would suffer with types declaration:

image

And a typescript config is necessary to me.

API design

Source Code

// config/src/index.ts

import type {Config} from '@docusaurus/types'

// here is a sample of async config, and it would be also OK to just put a Config here
export const configCreatorAsync = async (): Promise<Config> => ({
  ...
  baseUrl: '/',
  docs: {...},
  blog:{...},
  ...
})

export default configCreatorAsync
// config/tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",

    "module": "commonjs", // docusaturus is based on CJS now
    "target": "esnext",   // to make the transpiled js more readable than es5 or like

    "outDir": "../..",    // directly output all the generated files under current website root dir, so **[important]**
                          // prevent the js failing to run in case of any path problems
    "rootDir": "../..",   // keep the project structure

    "resolveJsonModule": true,   // json support
    "esModuleInterop": true,     // esm support
    "moduleResolution": "node",  // node support

    "skipLibCheck": true,        // ensure true to avoid annoying type inspection errors
    "skipDefaultLibCheck": true, // the same as above 

    "sourceMap": false,          // unnecessary to generate map
    "declaration": false         // unnessary to genrate d.ts            
  },
  "include": [
    "src/**/*.ts",
    ...     // other files we need to be imported by src under src, e.g. my `../src/ds/tasks.ts`
  ],
  "exclude": [
    "**/node_modules"
  ]
}
// package.json
{
  "scripts": {
    "prestart": "cd config && tsc",
    "start": "docusaurus start --config config/src/index.js",
  }
}

Attention

  • prevent using path alias in our ts config file, since it would introduce troubles when transpiling into js, tsconfig-paths or tsc-alias may be helpful if you need it.
  • It's ok to not use outDir and rootDir in tsconfig.json, but it would fail if using tsc-alias at the same time since a outDir is need.
  • It's ok to just write one ts config file just like what the docusaurus.config.js did, but the config would become harder to manage as you have seen.

Other Practices

I also tried to use webpack to pack all the ts files into one docusaurus.config.webpack.js file and almost succeded with these settings:

// webpack.config.ts

import path from "path"

import type {Configuration} from 'webpack/types'

import nodeExternals from 'webpack-node-externals'

const config: Configuration = {
  resolve: {
    extensions: [".tsx", ".ts", ".jsx", ".js"],
    alias: {
      // target for tsconfig.json, ref: https://webpack.js.org/configuration/resolve/#resolvealias
      "@site": path.resolve(__dirname, "../"),
    }
  },
  entry: "./src/index.ts",
  output: {
    filename: 'docusaurus.config.webpack.js',
    path: path.resolve(__dirname, ".."),
    library: { // --> IMPORTANT <--
      type: 'commonjs-module',
      export: 'default'
    }
  },
  target: 'node',             // must enable, otherwise can't resolve `fs|path`
  node: {
    __dirname: true          // /my-website/src/css/theme.css
    // __dirname: false      // /my-website/css/theme.css (default)
  },
  externals: [nodeExternals()],

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      }
    ],
  },
};


const isProduction = process.env.NODE_ENV === "production";

module.exports = () => {
  if (isProduction) {
    config.mode = "production";
  } else {
    config.mode = "development";
  }
  return config;
};

But it failed with the unknown error request argument is not a string, which seems raised by the webpack inner docusaurus.

Have you tried building it?

No response

Self-service

  • I'd be willing to contribute this feature to Docusaurus myself.
@MarkShawn2020 MarkShawn2020 added feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future. status: needs triage This issue has not been triaged by maintainers labels Aug 7, 2022
@Josh-Cena Josh-Cena removed the status: needs triage This issue has not been triaged by maintainers label Aug 7, 2022
@Josh-Cena
Copy link
Collaborator

Definitely on our roadmap. You can use ts-node to load a TS config: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/website/docusaurus.config.js

@MarkShawn2020
Copy link
Contributor Author

Definitely on our roadmap. You can use ts-node to load a TS config: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/website/docusaurus.config.js

GREAT JOB!

@Josh-Cena
Copy link
Collaborator

We'll keep it open. It's on our todo list.

@MarkShawn2020
Copy link
Contributor Author

MarkShawn2020 commented Aug 7, 2022

I just tried the script based on ts-node, it runs quite well !

But it would fail when using alias, e.g. @site, in our backend.

Since the ts-node has been used, it's natural now to combiine it with tsconfig-paths.

I modified like this:

'use strict';

// source:  https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/website/docusaurus.config.js
// ref of tsconfig-paths: https://github.com/dividab/tsconfig-paths#bootstrapping-with-explicit-params

+ require("tsconfig-paths").register({
+    baseUrl: "./",
+    paths: require("./tsconfig.json").compilerOptions.paths,
+ });

require('ts-node').register({
    scope: true,
    scopeDir: __dirname,
    swc: true,
    transpileOnly: true,
});

module.exports = require('./config/src/index.ts');

And a manual alias is in need since extend would let my IDE unhappy:

{
  "compilerOptions": {
    "resolveJsonModule": true, // can be omitted, maybe has been handled by ts-node 
    "esModuleInterop": true,   // cannot be omitted
    "paths": {                 // handle the path aliases
      "@site/*": ["./*"]
    }
  }
}

Thanks for all of your great work, you did save me a lot of time and enlighten me as well ~

@slorber
Copy link
Collaborator

slorber commented Aug 9, 2022

For reference Gatsby recently added support for TS config files. That's worth studying their solution for the final implementation: gatsbyjs/gatsby#34613

I also found this interesting: https://github.com/egoist/bundle-require

@slorber slorber changed the title A full typescript implementation for config Support TypeScript in Docusaurus config Aug 9, 2022
@rxliuli

This comment was marked as off-topic.

@Josh-Cena
Copy link
Collaborator

@rxliuli Node ESM is orthogonal to TS. Even if you write TS in an ESM-like syntax, you are still downleveling it to CJS at runtime. Native support for ESM is tracked in #6520.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants