diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 1fb53c8..bc98e9a 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -10,6 +10,7 @@
- [Creating a minimal Denops plugin](./tutorial/helloworld/creating-a-minimal-denops-plugin.md)
- [Adding Denops APIs](./tutorial/helloworld/adding-an-api.md)
- [Calling Vim features](./tutorial/helloworld/calling-vim-features.md)
+ - [Managing dependencies](./tutorial/helloworld/managing-dependencies.md)
- [Tutorial (Maze)](./tutorial/maze/README.md)
- [Utilizing third-party library](./tutorial/maze/utilizing-third-party-library.md)
- [Outputting content to buffer](./tutorial/maze/outputting-content-to-buffer.md)
diff --git a/src/getting-started/README.md b/src/getting-started/README.md
index 2ec1080..5983a57 100644
--- a/src/getting-started/README.md
+++ b/src/getting-started/README.md
@@ -22,7 +22,7 @@ $HOME
Next, write the following TypeScript code in `main.ts`:
```typescript,title=denops/denops-getting-started/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
+import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
export const main: Entrypoint = (denops) => {
denops.dispatcher = {
@@ -33,6 +33,12 @@ export const main: Entrypoint = (denops) => {
};
```
+> [!NOTE]
+>
+> This example uses direct URL imports for simplicity. The recommended approach
+> for managing dependencies is to use `deno.jsonc` with import maps, which
+> you'll learn about in the [tutorials](../tutorial.md).
+
## Activate the Plugin
Add the following line to your Vim or Neovim configuration file (e.g.,
diff --git a/src/getting-started/explanation.md b/src/getting-started/explanation.md
index 0a35d9c..63e497f 100644
--- a/src/getting-started/explanation.md
+++ b/src/getting-started/explanation.md
@@ -91,7 +91,7 @@ easily call.
In the Getting Started, we wrote the following code in the `main.ts` file:
```typescript
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
+import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
export const main: Entrypoint = (denops) => {
denops.dispatcher = {
@@ -107,7 +107,7 @@ Let's break down this code step by step.
### About Imports
```typescript
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
+import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
```
The first line imports the `Entrypoint` type from the [@denops/std] standard
@@ -215,7 +215,7 @@ For example, use
Vim's function instead of `denops.call` like:
```typescript
-import * as fn from "jsr:@denops/std@^7.0.0/function";
+import * as fn from "jsr:@denops/std@^8.0.0/function";
// Bad (result1 is `unknown`)
const result1 = await denops.call("expand", "%");
diff --git a/src/introduction.md b/src/introduction.md
index 0afa18c..58e4abf 100644
--- a/src/introduction.md
+++ b/src/introduction.md
@@ -18,9 +18,10 @@ features:
- **Unified codebase for Vim and Neovim**:
Denops provides a unified API for
both Vim and Neovim. You can write a plugin that functions on both Vim and
Neovim with a single codebase.
-- **No worries about dependency management**:
Deno includes a built-in
- dependency management system, allowing developers to write plugins with
- third-party libraries without concerns about dependency management.
+- **Modern dependency management**:
Deno's built-in dependency system with
+ import maps provides clean, maintainable dependency management. The workspace
+ configuration ensures each plugin's dependencies are isolated, preventing
+ conflicts when multiple Denops plugins are installed together.
- **Simple and efficient code**:
Deno utilizes the V8 engine, significantly
faster than Vim script. You can write a plugin with straightforward code,
without the need for complex optimizations solely for performance.
diff --git a/src/tutorial/helloworld/adding-an-api.md b/src/tutorial/helloworld/adding-an-api.md
index 5dbda21..ca543f1 100644
--- a/src/tutorial/helloworld/adding-an-api.md
+++ b/src/tutorial/helloworld/adding-an-api.md
@@ -7,7 +7,7 @@ Open `denops/denops-helloworld/main.ts` and rewrite the content with the
following code:
```typescript,title=denops/denops-helloworld/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
+import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
export const main: Entrypoint = (denops) => {
diff --git a/src/tutorial/helloworld/calling-vim-features.md b/src/tutorial/helloworld/calling-vim-features.md
index 2e2b5fe..dd6ed1a 100644
--- a/src/tutorial/helloworld/calling-vim-features.md
+++ b/src/tutorial/helloworld/calling-vim-features.md
@@ -5,7 +5,7 @@ the `denops` instance passed to the plugin's `main` function. You can rewrite
`main.ts` as follows to register the `DenopsHello` as a Vim command:
```typescript,title=denops/denops-helloworld/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
+import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
export const main: Entrypoint = (denops) => {
@@ -57,8 +57,11 @@ as a result.
## Next Steps
-In the next step, follow the tutorial to learn how to develop a real Denops
-plugin.
+Learn about managing dependencies with import maps for cleaner code:
+
+- [Managing dependencies](./managing-dependencies.md)
+
+Or jump to the maze tutorial to learn more advanced concepts:
- [Tutorial (Maze)](../../tutorial/maze/index.html)
- [API reference](https://jsr.io/@denops/std)
diff --git a/src/tutorial/helloworld/creating-a-minimal-denops-plugin.md b/src/tutorial/helloworld/creating-a-minimal-denops-plugin.md
index 5963ac7..0ec7146 100644
--- a/src/tutorial/helloworld/creating-a-minimal-denops-plugin.md
+++ b/src/tutorial/helloworld/creating-a-minimal-denops-plugin.md
@@ -32,7 +32,7 @@ denops-helloworld
Here is the content of the `denops/denops-helloworld/main.ts` file:
```typescript,title=denops/denops-helloworld/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
+import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
export const main: Entrypoint = (denops) => {
console.log("Hello, Denops from TypeScript!");
diff --git a/src/tutorial/helloworld/managing-dependencies.md b/src/tutorial/helloworld/managing-dependencies.md
new file mode 100644
index 0000000..5676b8a
--- /dev/null
+++ b/src/tutorial/helloworld/managing-dependencies.md
@@ -0,0 +1,120 @@
+# Managing Dependencies with Import Maps
+
+In the previous examples, we used direct URL imports like
+`jsr:@denops/std@^8.0.0`. While this works, the recommended approach for Denops
+plugins (v8.0.0+) is to use import maps with `deno.jsonc` for cleaner and more
+maintainable dependency management.
+
+## Why Use Import Maps?
+
+The main reason to use import maps is to avoid conflicts between multiple Denops
+plugins. Each Denops plugin must have a unique directory name under `denops/`,
+but root-level configuration files could potentially conflict:
+
+```
+# Multiple plugins installed:
+~/.vim/pack/plugins/start/plugin-a/
+├── deno.jsonc # Could conflict
+└── denops/plugin-a/ # Always unique
+
+~/.vim/pack/plugins/start/plugin-b/
+├── deno.jsonc # Could conflict
+└── denops/plugin-b/ # Always unique
+```
+
+Some plugin managers have a "merge" feature that combines plugin directories,
+but even without merging, placing configuration files in plugin-specific
+directories (`denops/plugin-name/`) ensures no conflicts can occur regardless of
+how plugins are installed or managed.
+
+## Setting Up Your Plugin Structure
+
+Update your `denops-helloworld` structure to include configuration files:
+
+```
+denops-helloworld/
+├── deno.jsonc # Development configuration
+├── denops/
+│ └── denops-helloworld/
+│ ├── deno.jsonc # Runtime dependencies
+│ └── main.ts
+└── plugin/
+ └── denops-helloworld.vim
+```
+
+### Root deno.jsonc (Development)
+
+Create a `deno.jsonc` in your repository root for workspace configuration:
+
+```json
+{
+ "workspace": [
+ "./denops/denops-helloworld"
+ ]
+}
+```
+
+This enables Deno commands like `deno fmt`, `deno lint`, and `deno test` to work
+from your project root and discover your plugin's configuration.
+
+### Plugin deno.jsonc (Runtime)
+
+Create `denops/denops-helloworld/deno.jsonc` for runtime dependencies:
+
+```json
+{
+ "imports": {
+ "@denops/std": "jsr:@denops/std@^8.0.0",
+ "@core/unknownutil": "jsr:@core/unknownutil@^4.3.0"
+ }
+}
+```
+
+## Updating Your Code
+
+With import maps configured, update your imports from:
+
+```typescript
+import type { Entrypoint } from "jsr:@denops/std@^8.0.0";
+import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
+```
+
+To cleaner versions:
+
+```typescript
+import type { Entrypoint } from "@denops/std";
+import { assert, is } from "@core/unknownutil";
+```
+
+## Alternative: import_map.json
+
+Denops also supports `import_map.json(c)` files, but they require more verbose
+configuration due to the
+[Import Maps Standard](https://github.com/WICG/import-maps):
+
+```json
+// denops/denops-helloworld/import_map.json
+{
+ "imports": {
+ "@denops/std": "jsr:@denops/std@^8.0.0",
+ "@denops/std/": "jsr:/@denops/std@^8.0.0/" // Required for submodules
+ }
+}
+```
+
+We recommend using `deno.jsonc` as it's less verbose and integrates better with
+Deno tooling. For more details about the differences, see the
+[Deno documentation](https://docs.deno.com/runtime/fundamentals/modules/#differentiating-between-imports-or-importmap-in-deno.json-and---import-map-option).
+
+> [!IMPORTANT]
+>
+> Import map features require Denops v8.0.0 or later. For older versions,
+> continue using direct URL imports.
+
+## Benefits
+
+1. **Cleaner imports**: No more long URLs in your code
+2. **Version management**: Update dependencies in one place
+3. **Better IDE support**: Auto-completion and type checking work seamlessly
+4. **No conflicts**: Each plugin manages its own dependencies
+5. **Development tools**: Format and lint your code from the project root
diff --git a/src/tutorial/maze/adjusting-maze-size-to-fit-the-window.md b/src/tutorial/maze/adjusting-maze-size-to-fit-the-window.md
index 4c62423..de208ca 100644
--- a/src/tutorial/maze/adjusting-maze-size-to-fit-the-window.md
+++ b/src/tutorial/maze/adjusting-maze-size-to-fit-the-window.md
@@ -7,10 +7,10 @@ to have a maze that fits the current window size.
Let's modify the plugin to ensure the generated maze fits the current window
size.
-```typescript,title=denops/denops-helloworld/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
-import * as fn from "jsr:@denops/std@^7.0.0/function";
-import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
+```typescript,title=denops/denops-maze/main.ts
+import type { Entrypoint } from "@denops/std";
+import * as fn from "@denops/std/function";
+import { Maze } from "maze_generator";
export const main: Entrypoint = (denops) => {
denops.dispatcher = {
diff --git a/src/tutorial/maze/creating-applicative-plugin.md b/src/tutorial/maze/creating-applicative-plugin.md
index 5c331dc..e43ce62 100644
--- a/src/tutorial/maze/creating-applicative-plugin.md
+++ b/src/tutorial/maze/creating-applicative-plugin.md
@@ -28,17 +28,30 @@ augroup denops_maze
augroup END
```
-Then, modify the `main.ts` file to accept the optional argument for a custom
+Then, update your `denops/denops-maze/deno.jsonc` to include the unknownutil
+dependency:
+
+```json,title=denops/denops-maze/deno.jsonc
+{
+ "imports": {
+ "@denops/std": "jsr:@denops/std@^8.0.0",
+ "@core/unknownutil": "jsr:@core/unknownutil@^4.3.0",
+ "maze_generator": "npm:@thewizardbear/maze_generator@^0.4.0"
+ }
+}
+```
+
+Now modify the `main.ts` file to accept the optional argument for a custom
opener, generate a maze that fits the current window size, configure the buffer
options to make it non-file readonly buffer, etc.
```typescript,title=denops/denops-maze/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
-import { batch, collect } from "jsr:@denops/std@^7.0.0/batch";
-import * as fn from "jsr:@denops/std@^7.0.0/function";
-import * as op from "jsr:@denops/std@^7.0.0/option";
-import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
-import { assert, is } from "jsr:@core/unknownutil@^4.3.0";
+import type { Entrypoint } from "@denops/std";
+import { batch, collect } from "@denops/std/batch";
+import * as fn from "@denops/std/function";
+import * as op from "@denops/std/option";
+import { Maze } from "maze_generator";
+import { assert, is } from "@core/unknownutil";
export const main: Entrypoint = (denops) => {
denops.dispatcher = {
diff --git a/src/tutorial/maze/outputting-content-to-buffer.md b/src/tutorial/maze/outputting-content-to-buffer.md
index 0cc0f5c..1c147b4 100644
--- a/src/tutorial/maze/outputting-content-to-buffer.md
+++ b/src/tutorial/maze/outputting-content-to-buffer.md
@@ -7,8 +7,8 @@ the maze to a buffer so that users can yank the maze with daily Vim operations!
Let's modify the code to make the generated maze output to a buffer.
```typescript,title=denops/denops-maze/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
-import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
+import type { Entrypoint } from "@denops/std";
+import { Maze } from "maze_generator";
export const main: Entrypoint = (denops) => {
denops.dispatcher = {
diff --git a/src/tutorial/maze/properly-configured-the-buffer.md b/src/tutorial/maze/properly-configured-the-buffer.md
index 018cb89..3f84e21 100644
--- a/src/tutorial/maze/properly-configured-the-buffer.md
+++ b/src/tutorial/maze/properly-configured-the-buffer.md
@@ -7,11 +7,11 @@ buffer after closure. Open the `main.ts` file and modify the `maze` method as
follows:
```typescript,title=denops/denops-maze/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
-import * as buffer from "jsr:@denops/std@^7.0.0/buffer";
-import * as fn from "jsr:@denops/std@^7.0.0/function";
-import * as op from "jsr:@denops/std@^7.0.0/option";
-import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
+import type { Entrypoint } from "@denops/std";
+import * as buffer from "@denops/std/buffer";
+import * as fn from "@denops/std/function";
+import * as op from "@denops/std/option";
+import { Maze } from "maze_generator";
export const main: Entrypoint = (denops) => {
denops.dispatcher = {
diff --git a/src/tutorial/maze/properly-create-a-virtual-buffer.md b/src/tutorial/maze/properly-create-a-virtual-buffer.md
index d15cb3f..c0f7a74 100644
--- a/src/tutorial/maze/properly-create-a-virtual-buffer.md
+++ b/src/tutorial/maze/properly-create-a-virtual-buffer.md
@@ -10,10 +10,10 @@ proper virtual buffer that concretizes the buffer content. Let's modify the
`main.ts` file as follows:
```typescript,title=denops/denops-maze/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
-import * as buffer from "jsr:@denops/std@^7.0.0/buffer";
-import * as fn from "jsr:@denops/std@^7.0.0/function";
-import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
+import type { Entrypoint } from "@denops/std";
+import * as buffer from "@denops/std/buffer";
+import * as fn from "@denops/std/function";
+import { Maze } from "maze_generator";
export const main: Entrypoint = (denops) => {
denops.dispatcher = {
diff --git a/src/tutorial/maze/reduce-the-number-of-rpc-calls.md b/src/tutorial/maze/reduce-the-number-of-rpc-calls.md
index 33bcd8f..87aa5b8 100644
--- a/src/tutorial/maze/reduce-the-number-of-rpc-calls.md
+++ b/src/tutorial/maze/reduce-the-number-of-rpc-calls.md
@@ -6,12 +6,12 @@ enhance performance by reducing the number of RPC calls using the `batch` module
from `@denops/std`. Let's revise the `main.ts` file as follows:
```typescript,title=denops/denops-maze/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
-import { batch, collect } from "jsr:@denops/std@^7.0.0/batch";
-import * as buffer from "jsr:@denops/std@^7.0.0/buffer";
-import * as fn from "jsr:@denops/std@^7.0.0/function";
-import * as op from "jsr:@denops/std@^7.0.0/option";
-import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
+import type { Entrypoint } from "@denops/std";
+import { batch, collect } from "@denops/std/batch";
+import * as buffer from "@denops/std/buffer";
+import * as fn from "@denops/std/function";
+import * as op from "@denops/std/option";
+import { Maze } from "maze_generator";
export const main: Entrypoint = (denops) => {
denops.dispatcher = {
diff --git a/src/tutorial/maze/utilizing-third-party-library.md b/src/tutorial/maze/utilizing-third-party-library.md
index 11a0914..19d5a01 100644
--- a/src/tutorial/maze/utilizing-third-party-library.md
+++ b/src/tutorial/maze/utilizing-third-party-library.md
@@ -19,18 +19,41 @@ directory tree will look like this:
```
~/denops-maze
+├── deno.jsonc
├── denops
│ └── denops-maze
+│ ├── deno.jsonc
│ └── main.ts
└── plugin
└── denops-maze.vim
```
+First, create the root `deno.jsonc` file for workspace configuration:
+
+```json,title=deno.jsonc
+{
+ "workspace": [
+ "./denops/denops-maze"
+ ]
+}
+```
+
+Then, create the `denops/denops-maze/deno.jsonc` file for runtime dependencies:
+
+```json,title=denops/denops-maze/deno.jsonc
+{
+ "imports": {
+ "@denops/std": "jsr:@denops/std@^8.0.0",
+ "maze_generator": "npm:@thewizardbear/maze_generator@^0.4.0"
+ }
+}
+```
+
The content of the `denops/denops-maze/main.ts` file will be:
```typescript,title=denops/denops-maze/main.ts
-import type { Entrypoint } from "jsr:@denops/std@^7.0.0";
-import { Maze } from "npm:@thewizardbear/maze_generator@^0.4.0";
+import type { Entrypoint } from "@denops/std";
+import { Maze } from "maze_generator";
export const main: Entrypoint = (denops) => {
denops.dispatcher = {