Skip to content

Commit

Permalink
feat: typescript support for config file (#2973)
Browse files Browse the repository at this point in the history
* feat: typescript support for config file

* chore: fix that Support for the experimental syntax 'classProperties' isn't currently enabled
  • Loading branch information
ulivz committed Dec 22, 2021
1 parent 19eeb14 commit daa6404
Show file tree
Hide file tree
Showing 44 changed files with 2,596 additions and 206 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
!.vuepress
packages/@vuepress/shared-utils/lib
packages/@vuepress/shared-utils/types
packages/vuepress/types
17 changes: 8 additions & 9 deletions .github/workflows/pull-request-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,19 @@ jobs:
pr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '12'
node-version: '14'
check-latest: true
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1

- uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-modules-
${{ runner.os }}-
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}

- name: Install dependencies
if: steps.yarn-cache.outputs.cache-hit != 'true'
Expand Down
8 changes: 7 additions & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ module.exports = {
['@babel/preset-env', { 'targets': { 'node': 'current' }}]
],
'plugins': [
'@babel/plugin-syntax-dynamic-import'
'@babel/plugin-syntax-dynamic-import',
[
'@babel/plugin-proposal-class-properties',
{
'loose': true
}
]
]
}
}
Expand Down
Binary file added changelog-unpublished/1.9/assets/1.9-lang.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
143 changes: 143 additions & 0 deletions changelog-unpublished/1.9/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# TypeScript Support for Config file

## Overview

![](./assets/1.9-overview.png)

## Features

### Support `.vuepress/config.ts`

Previously, VuePress only supported these configurations

- `.vuepress/config.js`
- `.vuepress/config.yml`
- `.vuepress/config.toml`

From now on, `.vuepress/config.ts` get officially supported.

### `defineConfig` helper for config intellisense

A helper function exposed at `vuepress/config`, which helps you to have type prompt:

```ts
import { defineConfig } from "vuepress/config";

export default defineConfig({
title: "VuePress",
description: "Vue-powered Static Site Generator"
// ...
});
```

### `Typed` Theme Config

By default, `defineConfig` helper leverages the theme config type from default theme:

```js
import { defineConfig } from "vuepress/config";

export default defineConfig({
themeConfig: {
repo: "vuejs/vuepress",
editLinks: true,
docsDir: "packages/docs/docs"
// Type is `DefaultThemeConfig`
}
});
```

If you use a custom theme, you can use the `defineConfig4CustomTheme` helper with ability to pass generic type for your theme:

```ts
import { defineConfig4CustomTheme } from "vuepress/config";

interface MyThemeConfig {
hello: string;
}

export default defineConfig4CustomTheme<MyThemeConfig>(
{
themeConfig: {
// Type is `MyThemeConfig`
hello: "vuepress"
}
},
```
### Type Inferences for Official Plugins
From now, you’ll be able to enjoy the type prompt of the official plugins:
![](./assets/1.9-official-plugin-tuple-usage.png)
Options of the official plugins certainly have type prompts, **Both [Tuple Style](https://vuepress.vuejs.org/plugin/using-a-plugin.html#plugin-options) and [Object Style](https://vuepress.vuejs.org/plugin/using-a-plugin.html#plugin-options), and [Plugin Shorthand](https://vuepress.vuejs.org/plugin/using-a-plugin.html#plugin-shorthand) support type inference**:
- Tuple Style:
![](./assets/1.9-official-plugin-options.png)
```ts
import { defineConfig } from 'vuepress/config'

export default defineConfig({
plugins: [
[
'@vuepress/pwa',
{
serviceWorker: true
}
]
]
})
```
- Object Style:
```ts
import { defineConfig } from 'vuepress/config'

export default defineConfig({
plugins: {
'@vuepress/pwa': {
serviceWorker: true
}
}
})
```
The illustration snapshot is omitted here, you can try it yourself.
### ISO Language Code
Type inference supports [ISO Language Code](http://www.lingoes.net/en/translator/langcode.htm)
![](./assets/1.9-lang.png)
### Context API
VuePress's configuration can also be a function, while its first parameter is the current [app context](https://vuepress.vuejs.org/plugin/context-api.html#context-api):
```ts
import { defineConfig } from "vuepress/config";

export default defineConfig(ctx => ({
// do not execute babel compilation under development
evergreen: ctx.isProd
}));
```
## Limitations
It is worth noting that third-party plugins do not support [Plugin Shorthand](https://vuepress.vuejs.org/plugin/using-a-plugin.html#plugin-shorthand) if you're using [Tuple Style](https://vuepress.vuejs.org/plugin/using-a-plugin.html#plugin-options) to write your config, this is because from the perspective of the type system, the unknown shortcut is equivalent to `string`, which results in the failure of type inference.
By default, only officially maintained and plugins under [VuePress Community](https://vuepress-community.netlify.app/en/) support shortcut, feel free to submit pull request to add your plugin at this [file](https://github.com/vuejs/vuepress/blob/master/packages/vuepress/types/third-party-plugins.ts).
## Credits
- [bundle-require](https://github.com/egoist/bundle-require) (by [@egoist](https://github.com/egoist)): we leverage it under the hood to resolve user's config, which is powered by `esbuild`.
- [vscode-ts-in-markdown](https://github.com/Amour1688/vscode-ts-in-markdown) (by [@Amour1688](https://github.com/Amour1688)): this documentation is powered by this plugin, which make type checking possible in markdown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
]
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "7",
"@commitlint/cli": "^8.2.0",
"@commitlint/config-conventional": "^8.2.0",
"@nomadland/mono": "0.3.3",
Expand All @@ -68,6 +69,6 @@
"lint-staged": "^9.3.0",
"minimist": "^1.2.0",
"sort-package-json": "^1.24.0",
"typescript": "^3.6.3"
"typescript": "4.5.2"
}
}
2 changes: 1 addition & 1 deletion packages/@vuepress/core/lib/node/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ module.exports = class App {
if (this.options.siteConfig) {
this.siteConfig = this.options.siteConfig
} else {
let siteConfig = loadConfig(this.vuepressDir)
let siteConfig = await loadConfig(this.vuepressDir)
if (isFunction(siteConfig)) {
siteConfig = await siteConfig(this)
}
Expand Down
8 changes: 7 additions & 1 deletion packages/@vuepress/core/lib/node/loadConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ const tomlParser = require('toml')
* Expose loadConfig.
*/

module.exports = function loadConfig (vuepressDir, bustCache = true) {
module.exports = async function loadConfig (vuepressDir, bustCache = true) {
const configPath = path.resolve(vuepressDir, 'config.js')
const configYmlPath = path.resolve(vuepressDir, 'config.yml')
const configTomlPath = path.resolve(vuepressDir, 'config.toml')
const configTsPath = path.resolve(vuepressDir, 'config.ts')

if (bustCache) {
delete require.cache[configPath]
Expand All @@ -25,6 +26,11 @@ module.exports = function loadConfig (vuepressDir, bustCache = true) {
let siteConfig = {}
if (fs.existsSync(configYmlPath)) {
siteConfig = parseConfig(configYmlPath)
} else if (fs.existsSync(configTsPath)) {
const { mod } = await require('bundle-require').bundleRequire({
filepath: configTsPath
})
siteConfig = mod.default || mod
} else if (fs.existsSync(configTomlPath)) {
siteConfig = parseConfig(configTomlPath)
} else if (fs.existsSync(configPath)) {
Expand Down
2 changes: 2 additions & 0 deletions packages/@vuepress/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@
"@vuepress/shared-utils": "1.8.3",
"autoprefixer": "^9.5.1",
"babel-loader": "^8.0.4",
"bundle-require": "2.1.8",
"cache-loader": "^3.0.0",
"chokidar": "^2.0.3",
"connect-history-api-fallback": "^1.5.0",
"copy-webpack-plugin": "^5.0.2",
"core-js": "^3.6.4",
"cross-spawn": "^6.0.5",
"css-loader": "^2.1.1",
"esbuild": "0.14.7",
"file-loader": "^3.0.1",
"js-yaml": "^3.13.1",
"lru-cache": "^5.1.1",
Expand Down
Loading

0 comments on commit daa6404

Please sign in to comment.