Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 61 additions & 6 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ plugins, rehype plugins, the git repository URL, and more.
Below you can see an example of how to pass these options to Docfy.

```js
const Docfy = require('@docfy/core');
import Docfy from '@docfy/core';

const docfy = new Docfy({
plugins: [],
Expand Down Expand Up @@ -42,10 +42,10 @@ const docfy = new Docfy({
Example:

```js
const hbs = require('remark-hbs');
const autolinkHeadings = require('remark-autolink-headings');
import hbs from 'remark-hbs';
import codeImport from 'remark-code-import';

const remarkPlugins = [autolinkHeadings, hbs];
const remarkPlugins = [codeImport, hbs];

//...
```
Expand All @@ -56,9 +56,9 @@ In case the plugin has options, you can specify as the example below:
// ..
const remarkPlugins = [
[
autolinkHeadings,
codeImport,
{
behavior: 'wrap',
preserveTrailingNewline: true,
},
],
];
Expand All @@ -70,6 +70,61 @@ const remarkPlugins = [

You can also pass options to rehype plugins the same way as remark plugins.

```js
import autolinkHeadings from 'rehype-autolink-headings';
import highlight from 'rehype-highlight';

const rehypePlugins = [[autolinkHeadings, { behavior: 'wrap' }], highlight];
```

Most of the remark/rehype ecosystem is ESM-only. Docfy requires a Node version
that supports `require()` of ES modules, so you can load those plugins from a
CommonJS config file as well — just remember that `require()` hands you the
module namespace:

```js
// .docfy-config.js (CommonJS)
const highlight = require('rehype-highlight').default;
```

#### Syntax highlighting

Highlighting is a rehype concern. Use
[`rehype-highlight`](https://github.com/rehypejs/rehype-highlight) (highlight.js)
or [`rehype-prism-plus`](https://github.com/timlrx/rehype-prism-plus) (Prism).
The older `remark-highlight.js` and `@mapbox/rehype-prism` packages are
unmaintained and pinned to highlight.js 10 / old refractor builds; they do not
work with the current unified stack.

For Ember, `rehype-highlight` with
[`highlightjs-glimmer`](https://github.com/NullVoxPopuli/highlightjs-glimmer)
gives proper `gjs`/`gts`/`hbs` highlighting:

```js
import highlight from 'rehype-highlight';
import { glimmer } from 'highlightjs-glimmer';
import { common } from 'lowlight';

const rehypePlugins = [
[
highlight,
{
languages: { ...common, glimmer, hbs: glimmer, handlebars: glimmer },
aliases: { javascript: ['gjs'], typescript: ['gts'] },
},
],
];
```

> **`languages` replaces the defaults, it does not extend them.**
> `rehype-highlight` uses `options.languages || common`, so passing your own map
> silently turns off highlighting for every other language. Spread lowlight's
> `common` back in (add `lowlight` as a dependency to import it).


If your app also depends on `highlight.js` directly, leave that dependency
alone — `rehype-highlight` brings its own copy through `lowlight`.

### `staticAssetsPath`

• **staticAssetsPath**? : _string_ - The static asset path to be used in the URL. Assets such as images are considered static.
Expand Down
87 changes: 86 additions & 1 deletion docs/ember/ember-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ order: 3
## Prerequisites

- Classic Ember CLI application
- Node `^20.19.0 || >=22.12.0`
- `@docfy/ember` for runtime components (covered in [Tutorial](./tutorial.md))

## Installation
Expand All @@ -35,7 +36,91 @@ module.exports = {
};
```

> **Note**: Ember CLI integration only supports CommonJS format (`.js` files with `module.exports`). ESM configuration files (`.mjs`) are not supported due to Ember CLI's synchronous build process. For ESM config support, consider using [@docfy/ember-vite](./ember-vite.md) instead.
`.docfy-config.js`, `.docfy-config.mjs` and `.docfy-config.cjs` are all
supported, and the file is loaded synchronously either way — Node's support for
`require()` of ES modules means the classic build no longer has to care which
module format you picked.

The same applies to the plugins you load from it. Most of the remark/rehype
ecosystem is ESM-only these days, and a CommonJS config can `require()` those
plugins directly; `require()` returns the module namespace, so reach for
`.default`:

```js
// .docfy-config.js
const path = require('path');
const highlight = require('rehype-highlight').default;
const autolinkHeadings = require('rehype-autolink-headings').default;

module.exports = {
rehypePlugins: [[autolinkHeadings, { behavior: 'wrap' }], highlight],
sources: [
{
root: path.join(__dirname, 'docs'),
pattern: '**/*.md',
urlPrefix: 'docs',
},
],
};
```

Or the same thing as ESM, where imports need no unwrapping:

```js
// .docfy-config.mjs
import path from 'path';
import highlight from 'rehype-highlight';
import autolinkHeadings from 'rehype-autolink-headings';

export default {
rehypePlugins: [[autolinkHeadings, { behavior: 'wrap' }], highlight],
sources: [
{
root: path.join(import.meta.dirname, 'docs'),
pattern: '**/*.md',
urlPrefix: 'docs',
},
],
};
```

> **The one limitation**: a config using **top-level `await`** cannot be loaded,
> because Ember CLI's build is synchronous. Docfy fails with an explicit message
> if you try. Move the async work into a Docfy plugin, or use
> [@docfy/ember-vite](./ember-vite.md), which loads the config asynchronously.

### Syntax highlighting

Highlighting runs as a rehype plugin. Combining `rehype-highlight` with
[`highlightjs-glimmer`](https://github.com/NullVoxPopuli/highlightjs-glimmer)
gives real `gjs`/`gts`/`hbs` highlighting instead of the handlebars grammar:

```js
// .docfy-config.js
const highlight = require('rehype-highlight').default;
const { glimmer } = require('highlightjs-glimmer');
const { common } = require('lowlight');

module.exports = {
rehypePlugins: [
[
highlight,
{
// `languages` replaces rehype-highlight's defaults rather than
// extending them, so spread lowlight's `common` back in.
languages: { ...common, glimmer, hbs: glimmer, handlebars: glimmer },
aliases: { javascript: ['gjs'], typescript: ['gts'] },
},
],
],
// ...
};
```

Docfy escapes `{{` inside code blocks for you, after highlighting has run, so
the highlighted markup does not get parsed as a mustache by Ember's template
compiler. You do not need `remarkHbsOptions.escapeCurliesCode` for this — Docfy
manages that option itself.

## Ember CLI-Specific Features

Expand Down
16 changes: 11 additions & 5 deletions docs/ember/ember-vite.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,36 @@ export default defineConfig({

### Configuration File

For better organization, use a separate configuration file. Create `docfy.config.js` or `docfy.config.mjs`:
For better organization, use a separate configuration file. Create `docfy.config.mjs` or `docfy.config.js`:

```js
// docfy.config.js
const path = require('path');
// docfy.config.mjs
import path from 'path';
import highlight from 'rehype-highlight';

module.exports = {
export default {
sources: [
{
root: path.join(__dirname, 'docs'),
root: path.join(import.meta.dirname, 'docs'),
pattern: '**/*.md',
urlPrefix: 'docs',
},
],
remarkPlugins: [
// Add remark plugins
],
rehypePlugins: [highlight],
repository: {
url: 'https://github.com/username/repo',
editBranch: 'main',
},
};
```

The config is loaded with a dynamic `import()`, so CommonJS and ESM both work,
and unlike the classic Ember CLI integration this one accepts top-level
`await`.

Then use it in your Vite config:

```js
Expand Down
148 changes: 148 additions & 0 deletions docs/ember/upgrade-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,154 @@ order: 6

This guide helps you upgrade between different versions of Docfy's Ember integration packages.

## Upgrading to v0.13.x

Version 0.13.0 moves Docfy onto the current unified/remark stack (unified 11,
remark 11, rehype 11). Docfy's own packages are now ES modules.

### Node version

Docfy now requires Node `^20.19.0 || >=22.12.0`. This is not negotiable: those
are the versions where `require()` of an ES module works, which is what allows
the classic Ember CLI build and CommonJS config files to keep working against
ESM-only packages.

### Your config file keeps working

There is no forced migration to `.mjs`. A CommonJS `.docfy-config.js` is still
fully supported, including `require()`-ing ESM-only remark/rehype plugins.
`@docfy/ember-cli` now also accepts `.docfy-config.mjs` and `.docfy-config.cjs`.

The one thing a classic-build config cannot do is use top-level `await` — Ember
CLI's build is synchronous. Docfy raises an explicit error if it finds one.
`@docfy/ember-vite` has no such restriction.

### Syntax highlighting must move to rehype

This is the change most projects will actually have to make. `remark-highlight.js`
and `@mapbox/rehype-prism` are unmaintained and pinned to highlight.js 10 / old
refractor builds, and they do not work with unified 11.

```diff
-import highlight from 'remark-highlight.js';
+import highlight from 'rehype-highlight';

- remarkPlugins: [highlight],
+ rehypePlugins: [highlight],
```

Use [`rehype-highlight`](https://github.com/rehypejs/rehype-highlight) for
highlight.js or [`rehype-prism-plus`](https://github.com/timlrx/rehype-prism-plus)
for Prism. Because highlight.js 11 now works, so does
[`highlightjs-glimmer`](https://github.com/NullVoxPopuli/highlightjs-glimmer):

```js
import highlight from 'rehype-highlight';
import { glimmer } from 'highlightjs-glimmer';
import { common } from 'lowlight';

export default {
rehypePlugins: [
[
highlight,
{
languages: { ...common, glimmer, hbs: glimmer, handlebars: glimmer },
aliases: { javascript: ['gjs'], typescript: ['gts'] },
},
],
],
};
```

> **`languages` replaces the defaults, it does not extend them.**
> `rehype-highlight` uses `options.languages || common`, so passing your own map
> silently turns off highlighting for every other language. Spread lowlight's
> `common` back in (add `lowlight` as a dependency to import it).

**If your app depends on `highlight.js` directly, leave that dependency where it
is.** `rehype-highlight` brings its own copy via `lowlight`. Bumping a direct
`highlight.js` 10 dependency to 11 at the same time is an unrelated migration
and will break any code of yours that registers languages by hand.

### Curly escaping moved after highlighting

Docfy escapes `{{` inside code blocks so Ember's template compiler does not read
them as mustaches. That used to happen while the document was still markdown,
which broke as soon as a rehype highlighter started injecting `<span>`s into code
blocks afterwards. Docfy now escapes at the HTML stage, after all rehype plugins
have run.

As a result, Docfy manages `remarkHbsOptions.escapeCurliesCode` and
`escapeCurliesInlineCode` itself. **Remove those options from your config** if you
set them; setting `escapeCurliesCode: false` alongside a highlighter is what
produces errors like:

```
Parse error on line 23:
...tuation mustache">{{<span class="hljs-cl
-----------------------^
```

### Other deprecated plugins

```diff
-import autolinkHeadings from 'remark-autolink-headings';
+import autolinkHeadings from 'rehype-autolink-headings';

- remarkPlugins: [autolinkHeadings],
+ rehypePlugins: [[autolinkHeadings, { behavior: 'wrap' }]],
```

`remark-slug` and `remark-autolink-headings` are both deprecated. Docfy no longer
depends on `remark-slug` at all — heading ids are generated internally and are
unchanged, so your anchor links keep working.

Also worth bumping if you use them: `remark-code-import` to `^1.0.0`,
`remark-math` to `^6.0.0`, `rehype-katex` to `^7.0.0`. Note that `remark-math` 6
renders un-`katex`'d math as `<code class="language-math">` rather than
`<span class="math">`.

#### remark-code-import needs a `rootDir`

`remark-code-import` v1 refuses to read files outside `rootDir`, which defaults
to the process working directory. In a monorepo — or any setup where the docs
live outside the app being built — you have to say where the root is:

```js
import path from 'path';
import codeImport from 'remark-code-import';

export default {
remarkPlugins: [[codeImport, { rootDir: path.join(import.meta.dirname, '..') }]],
};
```

Without it you get `Attempted to import code from "…", which is outside from the
rootDir "…"`.

### If you use @docfy/core directly

Plain `require('@docfy/core')` now returns a module namespace rather than the
class:

```diff
-const Docfy = require('@docfy/core');
+const Docfy = require('@docfy/core').default;
```

TypeScript consumers using `import Docfy from '@docfy/core'` with
`esModuleInterop`, and anything already using ESM `import`, need no change.

Deep imports from ESM need a file extension:

```diff
-import plugin from '@docfy/core/lib/plugin';
+import plugin from '@docfy/core/lib/plugin.js';
```

Type-only imports such as `@docfy/core/lib/types` are erased at compile time and
work either way.

## Upgrading to v0.10.x

Version 0.10.0 introduced a major architectural change with the new package structure. This section helps you migrate from previous versions to the new modular architecture.
Expand Down
Loading
Loading