Skip to content

Commit d0c8a62

Browse files
authored
Merge pull request #18 from vim-denops/update-denops-docs-import-maps
docs: Update to recommend workspace + deno.jsonc for dependency management
2 parents 13390fa + a6b3b3c commit d0c8a62

15 files changed

+209
-42
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- [Creating a minimal Denops plugin](./tutorial/helloworld/creating-a-minimal-denops-plugin.md)
1111
- [Adding Denops APIs](./tutorial/helloworld/adding-an-api.md)
1212
- [Calling Vim features](./tutorial/helloworld/calling-vim-features.md)
13+
- [Managing dependencies](./tutorial/helloworld/managing-dependencies.md)
1314
- [Tutorial (Maze)](./tutorial/maze/README.md)
1415
- [Utilizing third-party library](./tutorial/maze/utilizing-third-party-library.md)
1516
- [Outputting content to buffer](./tutorial/maze/outputting-content-to-buffer.md)

src/getting-started/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ $HOME
2222
Next, write the following TypeScript code in `main.ts`:
2323

2424
```typescript,title=denops/denops-getting-started/main.ts
25-
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
25+
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
2626

2727
export const main: Entrypoint = (denops) => {
2828
denops.dispatcher = {
@@ -33,6 +33,12 @@ export const main: Entrypoint = (denops) => {
3333
};
3434
```
3535

36+
> [!NOTE]
37+
>
38+
> This example uses direct URL imports for simplicity. The recommended approach
39+
> for managing dependencies is to use `deno.jsonc` with import maps, which
40+
> you'll learn about in the [tutorials](../tutorial.md).
41+
3642
## Activate the Plugin
3743

3844
Add the following line to your Vim or Neovim configuration file (e.g.,

src/getting-started/explanation.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ easily call.
9191
In the Getting Started, we wrote the following code in the `main.ts` file:
9292

9393
```typescript
94-
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
94+
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
9595

9696
export const main: Entrypoint = (denops) => {
9797
denops.dispatcher = {
@@ -107,7 +107,7 @@ Let's break down this code step by step.
107107
### About Imports
108108

109109
```typescript
110-
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
110+
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
111111
```
112112

113113
The first line imports the `Entrypoint` type from the [@denops/std] standard
@@ -215,7 +215,7 @@ For example, use
215215
Vim's function instead of `denops.call` like:
216216

217217
```typescript
218-
import * as fn from "jsr:@denops/std@^7.0.0/function";
218+
import * as fn from "jsr:@denops/std@^8.0.0/function";
219219

220220
// Bad (result1 is `unknown`)
221221
const result1 = await denops.call("expand", "%");

src/introduction.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ features:
1818
- **Unified codebase for Vim and Neovim**:<br>Denops provides a unified API for
1919
both Vim and Neovim. You can write a plugin that functions on both Vim and
2020
Neovim with a single codebase.
21-
- **No worries about dependency management**:<br>Deno includes a built-in
22-
dependency management system, allowing developers to write plugins with
23-
third-party libraries without concerns about dependency management.
21+
- **Modern dependency management**:<br>Deno's built-in dependency system with
22+
import maps provides clean, maintainable dependency management. The workspace
23+
configuration ensures each plugin's dependencies are isolated, preventing
24+
conflicts when multiple Denops plugins are installed together.
2425
- **Simple and efficient code**:<br>Deno utilizes the V8 engine, significantly
2526
faster than Vim script. You can write a plugin with straightforward code,
2627
without the need for complex optimizations solely for performance.

src/tutorial/helloworld/adding-an-api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Open `denops/denops-helloworld/main.ts` and rewrite the content with the
77
following code:
88

99
```typescript,title=denops/denops-helloworld/main.ts
10-
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
10+
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
1111
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
1212

1313
export const main: Entrypoint = (denops) => {

src/tutorial/helloworld/calling-vim-features.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ the `denops` instance passed to the plugin's `main` function. You can rewrite
55
`main.ts` as follows to register the `DenopsHello` as a Vim command:
66

77
```typescript,title=denops/denops-helloworld/main.ts
8-
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
8+
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
99
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
1010

1111
export const main: Entrypoint = (denops) => {
@@ -57,8 +57,11 @@ as a result.
5757

5858
## Next Steps
5959

60-
In the next step, follow the tutorial to learn how to develop a real Denops
61-
plugin.
60+
Learn about managing dependencies with import maps for cleaner code:
61+
62+
- [Managing dependencies](./managing-dependencies.md)
63+
64+
Or jump to the maze tutorial to learn more advanced concepts:
6265

6366
- [Tutorial (Maze)](../../tutorial/maze/index.html)
6467
- [API reference](https://jsr.io/@denops/std)

src/tutorial/helloworld/creating-a-minimal-denops-plugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ denops-helloworld
3232
Here is the content of the `denops/denops-helloworld/main.ts` file:
3333

3434
```typescript,title=denops/denops-helloworld/main.ts
35-
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
35+
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
3636

3737
export const main: Entrypoint = (denops) => {
3838
console.log("Hello, Denops from TypeScript!");
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Managing Dependencies with Import Maps
2+
3+
In the previous examples, we used direct URL imports like
4+
`jsr:@denops/std@^8.0.0`. While this works, the recommended approach for Denops
5+
plugins (v8.0.0+) is to use import maps with `deno.jsonc` for cleaner and more
6+
maintainable dependency management.
7+
8+
## Why Use Import Maps?
9+
10+
The main reason to use import maps is to avoid conflicts between multiple Denops
11+
plugins. Each Denops plugin must have a unique directory name under `denops/`,
12+
but root-level configuration files could potentially conflict:
13+
14+
```
15+
# Multiple plugins installed:
16+
~/.vim/pack/plugins/start/plugin-a/
17+
├── deno.jsonc # Could conflict
18+
└── denops/plugin-a/ # Always unique
19+
20+
~/.vim/pack/plugins/start/plugin-b/
21+
├── deno.jsonc # Could conflict
22+
└── denops/plugin-b/ # Always unique
23+
```
24+
25+
Some plugin managers have a "merge" feature that combines plugin directories,
26+
but even without merging, placing configuration files in plugin-specific
27+
directories (`denops/plugin-name/`) ensures no conflicts can occur regardless of
28+
how plugins are installed or managed.
29+
30+
## Setting Up Your Plugin Structure
31+
32+
Update your `denops-helloworld` structure to include configuration files:
33+
34+
```
35+
denops-helloworld/
36+
├── deno.jsonc # Development configuration
37+
├── denops/
38+
│ └── denops-helloworld/
39+
│ ├── deno.jsonc # Runtime dependencies
40+
│ └── main.ts
41+
└── plugin/
42+
└── denops-helloworld.vim
43+
```
44+
45+
### Root deno.jsonc (Development)
46+
47+
Create a `deno.jsonc` in your repository root for workspace configuration:
48+
49+
```json
50+
{
51+
"workspace": [
52+
"./denops/denops-helloworld"
53+
]
54+
}
55+
```
56+
57+
This enables Deno commands like `deno fmt`, `deno lint`, and `deno test` to work
58+
from your project root and discover your plugin's configuration.
59+
60+
### Plugin deno.jsonc (Runtime)
61+
62+
Create `denops/denops-helloworld/deno.jsonc` for runtime dependencies:
63+
64+
```json
65+
{
66+
"imports": {
67+
"@denops/std": "jsr:@denops/std@^8.0.0",
68+
"@core/unknownutil": "jsr:@core/unknownutil@^4.3.0"
69+
}
70+
}
71+
```
72+
73+
## Updating Your Code
74+
75+
With import maps configured, update your imports from:
76+
77+
```typescript
78+
import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
79+
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
80+
```
81+
82+
To cleaner versions:
83+
84+
```typescript
85+
import type { Entrypoint } from "@denops/std";
86+
import { assert, is } from "@core/unknownutil";
87+
```
88+
89+
## Alternative: import_map.json
90+
91+
Denops also supports `import_map.json(c)` files, but they require more verbose
92+
configuration due to the
93+
[Import Maps Standard](https://github.com/WICG/import-maps):
94+
95+
```json
96+
// denops/denops-helloworld/import_map.json
97+
{
98+
"imports": {
99+
"@denops/std": "jsr:@denops/std@^8.0.0",
100+
"@denops/std/": "jsr:/@denops/std@^8.0.0/" // Required for submodules
101+
}
102+
}
103+
```
104+
105+
We recommend using `deno.jsonc` as it's less verbose and integrates better with
106+
Deno tooling. For more details about the differences, see the
107+
[Deno documentation](https://docs.deno.com/runtime/fundamentals/modules/#differentiating-between-imports-or-importmap-in-deno.json-and---import-map-option).
108+
109+
> [!IMPORTANT]
110+
>
111+
> Import map features require Denops v8.0.0 or later. For older versions,
112+
> continue using direct URL imports.
113+
114+
## Benefits
115+
116+
1. **Cleaner imports**: No more long URLs in your code
117+
2. **Version management**: Update dependencies in one place
118+
3. **Better IDE support**: Auto-completion and type checking work seamlessly
119+
4. **No conflicts**: Each plugin manages its own dependencies
120+
5. **Development tools**: Format and lint your code from the project root

src/tutorial/maze/adjusting-maze-size-to-fit-the-window.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ to have a maze that fits the current window size.
77
Let's modify the plugin to ensure the generated maze fits the current window
88
size.
99

10-
```typescript,title=denops/denops-helloworld/main.ts
11-
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
12-
import * as fn from "jsr:@denops/std@^7.0.0/function";
13-
import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
10+
```typescript,title=denops/denops-maze/main.ts
11+
import type { Entrypoint } from "@denops/std";
12+
import * as fn from "@denops/std/function";
13+
import { Maze } from "maze_generator";
1414

1515
export const main: Entrypoint = (denops) => {
1616
denops.dispatcher = {

src/tutorial/maze/creating-applicative-plugin.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,30 @@ augroup denops_maze
2828
augroup END
2929
```
3030

31-
Then, modify the `main.ts` file to accept the optional argument for a custom
31+
Then, update your `denops/denops-maze/deno.jsonc` to include the unknownutil
32+
dependency:
33+
34+
```json,title=denops/denops-maze/deno.jsonc
35+
{
36+
"imports": {
37+
"@denops/std": "jsr:@denops/std@^8.0.0",
38+
"@core/unknownutil": "jsr:@core/unknownutil@^4.3.0",
39+
"maze_generator": "npm:@thewizardbear/maze_generator@^0.4.0"
40+
}
41+
}
42+
```
43+
44+
Now modify the `main.ts` file to accept the optional argument for a custom
3245
opener, generate a maze that fits the current window size, configure the buffer
3346
options to make it non-file readonly buffer, etc.
3447

3548
```typescript,title=denops/denops-maze/main.ts
36-
import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
37-
import { batch, collect } from "jsr:@denops/std@^7.0.0/batch";
38-
import * as fn from "jsr:@denops/std@^7.0.0/function";
39-
import * as op from "jsr:@denops/std@^7.0.0/option";
40-
import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
41-
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
49+
import type { Entrypoint } from "@denops/std";
50+
import { batch, collect } from "@denops/std/batch";
51+
import * as fn from "@denops/std/function";
52+
import * as op from "@denops/std/option";
53+
import { Maze } from "maze_generator";
54+
import { assert, is } from "@core/unknownutil";
4255

4356
export const main: Entrypoint = (denops) => {
4457
denops.dispatcher = {

0 commit comments

Comments
 (0)