Skip to content

Commit daa6404

Browse files
authored
feat: typescript support for config file (#2973)
* feat: typescript support for config file * chore: fix that Support for the experimental syntax 'classProperties' isn't currently enabled
1 parent 19eeb14 commit daa6404

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2596
-206
lines changed

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
!.vuepress
55
packages/@vuepress/shared-utils/lib
66
packages/@vuepress/shared-utils/types
7+
packages/vuepress/types

.github/workflows/pull-request-ci.yml

+8-9
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,19 @@ jobs:
77
pr:
88
runs-on: ubuntu-latest
99
steps:
10-
- uses: actions/checkout@v1
11-
- uses: actions/setup-node@v1
10+
- uses: actions/checkout@v2
11+
- uses: actions/setup-node@v2
1212
with:
13-
node-version: '12'
13+
node-version: '14'
14+
check-latest: true
1415
- name: Get yarn cache directory path
1516
id: yarn-cache-dir-path
1617
run: echo "::set-output name=dir::$(yarn cache dir)"
17-
- uses: actions/cache@v1
18+
19+
- uses: actions/cache@v2
1820
with:
19-
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
20-
key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }}
21-
restore-keys: |
22-
${{ runner.os }}-node-modules-
23-
${{ runner.os }}-
21+
path: '**/node_modules'
22+
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
2423

2524
- name: Install dependencies
2625
if: steps.yarn-cache.outputs.cache-hit != 'true'

babel.config.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ module.exports = {
55
['@babel/preset-env', { 'targets': { 'node': 'current' }}]
66
],
77
'plugins': [
8-
'@babel/plugin-syntax-dynamic-import'
8+
'@babel/plugin-syntax-dynamic-import',
9+
[
10+
'@babel/plugin-proposal-class-properties',
11+
{
12+
'loose': true
13+
}
14+
]
915
]
1016
}
1117
}
114 KB
Loading
Loading
Loading
Loading

changelog-unpublished/1.9/index.md

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# TypeScript Support for Config file
2+
3+
## Overview
4+
5+
![](./assets/1.9-overview.png)
6+
7+
## Features
8+
9+
### Support `.vuepress/config.ts`
10+
11+
Previously, VuePress only supported these configurations
12+
13+
- `.vuepress/config.js`
14+
- `.vuepress/config.yml`
15+
- `.vuepress/config.toml`
16+
17+
From now on, `.vuepress/config.ts` get officially supported.
18+
19+
### `defineConfig` helper for config intellisense
20+
21+
A helper function exposed at `vuepress/config`, which helps you to have type prompt:
22+
23+
```ts
24+
import { defineConfig } from "vuepress/config";
25+
26+
export default defineConfig({
27+
title: "VuePress",
28+
description: "Vue-powered Static Site Generator"
29+
// ...
30+
});
31+
```
32+
33+
### `Typed` Theme Config
34+
35+
By default, `defineConfig` helper leverages the theme config type from default theme:
36+
37+
```js
38+
import { defineConfig } from "vuepress/config";
39+
40+
export default defineConfig({
41+
themeConfig: {
42+
repo: "vuejs/vuepress",
43+
editLinks: true,
44+
docsDir: "packages/docs/docs"
45+
// Type is `DefaultThemeConfig`
46+
}
47+
});
48+
```
49+
50+
If you use a custom theme, you can use the `defineConfig4CustomTheme` helper with ability to pass generic type for your theme:
51+
52+
```ts
53+
import { defineConfig4CustomTheme } from "vuepress/config";
54+
55+
interface MyThemeConfig {
56+
hello: string;
57+
}
58+
59+
export default defineConfig4CustomTheme<MyThemeConfig>(
60+
{
61+
themeConfig: {
62+
// Type is `MyThemeConfig`
63+
hello: "vuepress"
64+
}
65+
},
66+
```
67+
68+
### Type Inferences for Official Plugins
69+
70+
From now, you’ll be able to enjoy the type prompt of the official plugins:
71+
72+
![](./assets/1.9-official-plugin-tuple-usage.png)
73+
74+
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**:
75+
76+
- Tuple Style:
77+
78+
![](./assets/1.9-official-plugin-options.png)
79+
80+
```ts
81+
import { defineConfig } from 'vuepress/config'
82+
83+
export default defineConfig({
84+
plugins: [
85+
[
86+
'@vuepress/pwa',
87+
{
88+
serviceWorker: true
89+
}
90+
]
91+
]
92+
})
93+
```
94+
95+
- Object Style:
96+
97+
```ts
98+
import { defineConfig } from 'vuepress/config'
99+
100+
export default defineConfig({
101+
plugins: {
102+
'@vuepress/pwa': {
103+
serviceWorker: true
104+
}
105+
}
106+
})
107+
```
108+
109+
The illustration snapshot is omitted here, you can try it yourself.
110+
111+
112+
### ISO Language Code
113+
114+
Type inference supports [ISO Language Code](http://www.lingoes.net/en/translator/langcode.htm)
115+
116+
![](./assets/1.9-lang.png)
117+
118+
119+
### Context API
120+
121+
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):
122+
123+
```ts
124+
import { defineConfig } from "vuepress/config";
125+
126+
export default defineConfig(ctx => ({
127+
// do not execute babel compilation under development
128+
evergreen: ctx.isProd
129+
}));
130+
```
131+
132+
## Limitations
133+
134+
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.
135+
136+
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).
137+
138+
139+
140+
## Credits
141+
142+
- [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`.
143+
- [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.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
]
4646
},
4747
"devDependencies": {
48+
"@babel/plugin-proposal-class-properties": "7",
4849
"@commitlint/cli": "^8.2.0",
4950
"@commitlint/config-conventional": "^8.2.0",
5051
"@nomadland/mono": "0.3.3",
@@ -68,6 +69,6 @@
6869
"lint-staged": "^9.3.0",
6970
"minimist": "^1.2.0",
7071
"sort-package-json": "^1.24.0",
71-
"typescript": "^3.6.3"
72+
"typescript": "4.5.2"
7273
}
7374
}

packages/@vuepress/core/lib/node/App.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ module.exports = class App {
6161
if (this.options.siteConfig) {
6262
this.siteConfig = this.options.siteConfig
6363
} else {
64-
let siteConfig = loadConfig(this.vuepressDir)
64+
let siteConfig = await loadConfig(this.vuepressDir)
6565
if (isFunction(siteConfig)) {
6666
siteConfig = await siteConfig(this)
6767
}

packages/@vuepress/core/lib/node/loadConfig.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ const tomlParser = require('toml')
1212
* Expose loadConfig.
1313
*/
1414

15-
module.exports = function loadConfig (vuepressDir, bustCache = true) {
15+
module.exports = async function loadConfig (vuepressDir, bustCache = true) {
1616
const configPath = path.resolve(vuepressDir, 'config.js')
1717
const configYmlPath = path.resolve(vuepressDir, 'config.yml')
1818
const configTomlPath = path.resolve(vuepressDir, 'config.toml')
19+
const configTsPath = path.resolve(vuepressDir, 'config.ts')
1920

2021
if (bustCache) {
2122
delete require.cache[configPath]
@@ -25,6 +26,11 @@ module.exports = function loadConfig (vuepressDir, bustCache = true) {
2526
let siteConfig = {}
2627
if (fs.existsSync(configYmlPath)) {
2728
siteConfig = parseConfig(configYmlPath)
29+
} else if (fs.existsSync(configTsPath)) {
30+
const { mod } = await require('bundle-require').bundleRequire({
31+
filepath: configTsPath
32+
})
33+
siteConfig = mod.default || mod
2834
} else if (fs.existsSync(configTomlPath)) {
2935
siteConfig = parseConfig(configTomlPath)
3036
} else if (fs.existsSync(configPath)) {

packages/@vuepress/core/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@
3232
"@vuepress/shared-utils": "1.8.3",
3333
"autoprefixer": "^9.5.1",
3434
"babel-loader": "^8.0.4",
35+
"bundle-require": "2.1.8",
3536
"cache-loader": "^3.0.0",
3637
"chokidar": "^2.0.3",
3738
"connect-history-api-fallback": "^1.5.0",
3839
"copy-webpack-plugin": "^5.0.2",
3940
"core-js": "^3.6.4",
4041
"cross-spawn": "^6.0.5",
4142
"css-loader": "^2.1.1",
43+
"esbuild": "0.14.7",
4244
"file-loader": "^3.0.1",
4345
"js-yaml": "^3.13.1",
4446
"lru-cache": "^5.1.1",

0 commit comments

Comments
 (0)