-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1805573 - make it possible to write .stories.md or .stories.mdx d…
…ocumentation r=mstriemer,tgiles This patch both fixes the dependency issues that we were running into when writing `.stories.mdx` stories and gives us the ability to write `.stories.md` docs only vanilla markdown stories. To get the MDX stories working I had to clear out my `package-lock.json` and install `@mdx-js/react` with the `--legacy-peer-deps` flag as described here: storybookjs/storybook#18094 (comment) Let me know if you run into issues with installing dependencies and running Storybook given all the changes. There was a different solution I explored in January to enable MDX2 support, but I couldn't seem to resolve all the dependency version mismatch issues there anymore. There will probably be follow up work to update all of this after Storybook v7 is officially released in March. To enable us to write `.stories.md` docs only stories I added a custom Webpack loader that takes markdown and transforms it into docs only MDX, then runs that through all the other necessary loaders. There's definitely some follow up work here too - for example right now all our docs only pages get put in a "Docs" folder because I ran out of steam for exploring a way for us to specify/parse out a path and name for the docs stories. Differential Revision: https://phabricator.services.mozilla.com/D168268
- Loading branch information
1 parent
49de997
commit 3a587db
Showing
3 changed files
with
129 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,8 +11,9 @@ const projectRoot = path.resolve(__dirname, "../../../../"); | |
|
||
module.exports = { | ||
stories: [ | ||
"../**/*.stories.md", | ||
"../stories/**/*.stories.mdx", | ||
"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)", | ||
"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx|md)", | ||
`${projectRoot}/toolkit/**/*.stories.@(js|jsx|mjs|ts|tsx)`, | ||
], | ||
// Additions to the staticDirs might also need to get added to | ||
|
@@ -48,6 +49,12 @@ module.exports = { | |
config.resolve.alias[ | ||
"lit.all.mjs" | ||
] = `${projectRoot}/toolkit/content/widgets/vendor/lit.all.mjs`; | ||
// @mdx-js/[email protected] versions don't get hoisted to the root node_modules | ||
// folder due to the versions of React it accepts as a peer dependency. That | ||
// means we have to go one level deeper and look in the node_modules of | ||
// @storybook/addon-docs, which depends on @mdx-js/react. | ||
config.resolve.alias["@mdx-js/react"] = | ||
"browser/components/storybook/node_modules/@storybook/addon-docs/node_modules/@mdx-js/react"; | ||
|
||
// The @storybook/web-components project uses lit-html. Redirect it to our | ||
// bundled version. | ||
|
@@ -64,6 +71,41 @@ module.exports = { | |
loader: path.resolve(__dirname, "./chrome-uri-loader.js"), | ||
}); | ||
|
||
// We're adding a rule for files matching this pattern in order to support | ||
// writing docs only stories in plain markdown. | ||
const MD_STORY_REGEX = /(stories|story)\.md$/; | ||
|
||
// Find the existing rule for MDX stories. | ||
let mdxStoryTest = /(stories|story)\.mdx$/.toString(); | ||
let mdxRule = config.module.rules.find( | ||
rule => rule.test.toString() === mdxStoryTest | ||
); | ||
|
||
// Use a custom Webpack loader to transform our markdown stories into MDX, | ||
// then run our new MDX through the same loaders that Storybook usually uses | ||
// for MDX files. This is how we get a docs page from plain markdown. | ||
config.module.rules.push({ | ||
test: MD_STORY_REGEX, | ||
use: [ | ||
...mdxRule.use, | ||
{ loader: path.resolve(__dirname, "./markdown-story-loader.js") }, | ||
], | ||
}); | ||
|
||
// Find the existing rule for markdown files. | ||
let markdownTest = /\.md$/.toString(); | ||
let markdownRuleIndex = config.module.rules.findIndex( | ||
rule => rule.test.toString() === markdownTest | ||
); | ||
let markdownRule = config.module.rules[markdownRuleIndex]; | ||
|
||
// Modify the existing markdown rule so it doesn't process .stories.md | ||
// files, but still treats any other markdown files as asset/source. | ||
config.module.rules[markdownRuleIndex] = { | ||
...markdownRule, | ||
exclude: MD_STORY_REGEX, | ||
}; | ||
|
||
config.optimization = { | ||
splitChunks: false, | ||
runtimeChunk: false, | ||
|
79 changes: 79 additions & 0 deletions
79
browser/components/storybook/.storybook/markdown-story-loader.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
/* eslint-env node */ | ||
|
||
/** | ||
* This file contains a Webpack loader that takes markdown as its source and | ||
* outputs a docs only MDX Storybook story. This enables us to write docs only | ||
* pages in plain markdown by specifying a `.stories.md` extension. | ||
* | ||
* For more context on docs only stories, see: | ||
* https://storybook.js.org/docs/web-components/writing-docs/mdx#documentation-only-mdx | ||
* | ||
* The MDX generated by the loader will then get run through the same loaders | ||
* Storybook usually uses to transform MDX files. | ||
*/ | ||
|
||
const path = require("path"); | ||
|
||
/** | ||
* Takes a file path and returns a string to use as the story title, capitalized | ||
* and split into multiple words. The file name gets transformed into the story | ||
* name, which will be visible in the Storybook sidebar. For example, either: | ||
* | ||
* /stories/hello-world.stories.md or /stories/helloWorld.md | ||
* | ||
* will result in a story named "Hello World". | ||
* | ||
* @param {string} filePath - path of the file being processed. | ||
* @returns {string} The title of the story. | ||
*/ | ||
function getDocsStoryTitle(filePath) { | ||
let fileName = path.basename(filePath, ".stories.md"); | ||
let pascalCaseName = toPascalCase(fileName); | ||
return pascalCaseName.match(/[A-Z][a-z]+/g)?.join(" ") || pascalCaseName; | ||
} | ||
|
||
/** | ||
* Transforms a string into PascalCase e.g. hello-world becomes HelloWorld. | ||
* @param {string} str - String in any case. | ||
* @returns {string} The string converted to PascalCase. | ||
*/ | ||
function toPascalCase(str) { | ||
return str | ||
.match(/[a-z0-9]+/gi) | ||
.map(text => text[0].toUpperCase() + text.substring(1)) | ||
.join(""); | ||
} | ||
|
||
/** | ||
* The WebpackLoader export. Takes markdown as its source and returns a docs | ||
* only MDX story. For now we're filing all docs only stories under "Docs", but | ||
* that likely won't be desireable long term. | ||
* | ||
* @param {string} source - The markdown source to rewrite to MDX. | ||
*/ | ||
module.exports = function markdownStoryLoader(source) { | ||
// `this.resourcePath` is the path of the file being processed. | ||
let storyTitle = getDocsStoryTitle(this.resourcePath); | ||
|
||
// Unfortunately the indentation/spacing here seems to be important for the | ||
// MDX parser to know what to do in the next step of the Webpack process. | ||
let mdxSource = ` | ||
import { Meta, Description } from "@storybook/addon-docs"; | ||
<Meta | ||
title="Docs/${storyTitle}" | ||
parameters={{ | ||
previewTabs: { | ||
canvas: { hidden: true }, | ||
}, | ||
viewMode: "docs", | ||
}} | ||
/> | ||
${source}`; | ||
|
||
return mdxSource; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters