说明

之前使用过 Docz 来作为组件库文档搭建工具,它基于 gatsby , 提供了高度的定制化能力,但是截止 2021-06-22, Docz 停留在 v2.3.1(2020-04-05) 已经一年多,其所依赖的 gatsby 相关包,已经有了多个版本的更新,每次 安装 docz 都会在控制台收到大量的警告,虽然项目依然可以运行,但是为长久打算,决定放弃 Docz ,尝试基于 MDX 来搭建一个组件库

相关文章

  • 基于 next.js + mdx 搭建组件库文档项目(一) – 开发环境搭建
  • 基于 next.js + mdx 搭建组件库文档项目(二) – mdx 控件封装实现组件的演示与 Props 列表

预期计划

  • 使用 MDX 来作为文档的主要载体,这样组件库的文档还是通过 markdown 来写,同时在 markdown 中可以使用我们编写的 react 组件
  • 借助 react-docgen-typescript 来帮助将组件的 Props 类型输出到文档中
  • 借助 react-live 来实现源码展示、源码实时编译、源码映射组件展示
  • 使用 Next.js 中文 帮助搭建工程化开发环境,借助 Next.js 可以轻松实现 SSG(静态站点生成) SSR(服务器端渲染),与我们常用的 SPA (单页面应用)相比,会有更高的 SEO 优化空间
  • 封装与 docz 类似的 API(<Playground> <Props>),来实现组件的演示与Props展示
  • Typescript 作为主要的开发语言

1. 搭建 MDX + Next 开发环境

1. 使用 MDX 作为载体的优势

  • MDX 将 markdown 和 JSX 语法混合在一起并完美地 融入基于 JSX 的项目当中。
  • 一切皆组件: 导入(import) JSX 组件并 在 MDX 文档中直接渲染它们。
  • 基于 Markdown: Markdown 的简洁和优雅依然得到了保存, 只须在需要时才混入 JSX
  • 超级超级快: MDX 没有运行时,所有的编译都发生在 构建阶段。
  • 容易定制:Markdown 语法中的控件,都可以定制化样式

2. Next.js 介绍

Next.js 是一个 React 服务器端渲染应用框架,它提供了一整套的解决方案,使得开发者不需要花费更多的经历在 webpack 配置、router 配置、服务器配置等等问题上,只要专注于业务开发就可以了

优点

  1. 基本上不需要配置,模块打包、编译、优化等都不需要考虑
  2. 基于文件系统的路由,每个 pages 目录下的文件都是一个路由(有的时候可能不够灵活)
  3. 支持 SSG(静态站点生成) 和 SSR(服务器端渲染)
  4. API 简洁、使用方便、文档健全、支持页面快速刷新

3. MDX + Next.js 开发环境搭建

借助 create-next-app 创建一个 next 项目

npx create-next-app --typescript

可以观察到项目中有如下几个重要文件

├── next-env.d.ts # next 的 TS 类型文件
├── next.config.js # next 的配置文件
├── package.json
├── pages # 页面入口,也可以手动创建 src/pages 具有同样的路由功能
├── public # 静态资源存放
└── tsconfig.json

package.json 中会增加如下几个 script 命令

{"dev": "next dev","build": "next build",// "build": "next build && next export -o ../../docs", // 输出 SSG "start": "next start",
}

next.config.js 作为 next 的配置文件,用来配置项目打包情况,为了使项目支持引入 mdx 文件,我们需要追加一个插件 yarn add -D @next/mdx @mdx-js/loader

const withMDX = require("@next/mdx")({extension: /\.mdx?$/,options: {remarkPlugins: [], // mdx 支持的插件rehypePlugins: [] // mdx 支持的插件}
});module.exports = withMDX({pageExtensions: ["mdx", "tsx", 'ts', 'js', 'md'],
})

借助 @mdx-js/react 提供的 MDXProvider 来定义 markdown 语法的对应的 react 组件样式,可以在 这里 查看有那些 markdown 的语法是可以重新定义样式的

pages/_app.tsx 是在 pages 目录下比较特殊的一个文件,它是一个顶层组件,会在所有 page 中渲染,因此,一些全局样式,或者全局配置要在这个文件中定义

// pages/_app.tsx
import './globals.less';
import type { AppProps } from 'next/app';
import { MDXProvider } from '@mdx-js/react';
import { Wrapper, Paragraph, headings, UL, OL, Code } from '~controls';// 定义 mdx 中语法的映射组件
const components = {...headings,p: Paragraph,ol: OL,ul: UL,pre: Code,wrapper: Wrapper,
};// 顶级组件,所有 page 之间共享,用于全局样式,全局 state
const MyApp = ({ Component, pageProps }: AppProps) => {return (<MDXProvider components={components}><main id="document-scroll-container"><Component {...pageProps} /></main></MDXProvider>);
};
export default MyApp;

通过以上配置,就可以在普通页面中使用 mdx 的文件了

import ButtonMdx from '../../docs/core/Button/Code.mdx';export default function Home() {return <ButtonMdx />;
}

4. 怎么使用 less 定义样式

在 next.js 项目中内置了对 sass、css 的支持,且只有在 pages/_app.tsx 中才能使用 global css 其他页面中仅能使用 css module, 查看内置对 CSS 的支持 ,获得更多解释

很遗憾,我们的文档项目是给组件库使用的,而组件库已经使用了 less 作为样式的预编译语言,且为了方便组件库的使用者可以通过样式覆盖来自定义,组件库输出的时 global css

为了在 next.js 中使用 global + less ,我们需要对 next的 webpack 配置做些定制化,在 next.config.js 配置中有一个选项 webpack: (webpackConfig: T, nextConfig: K) => T ,我们借助这个配置来将默认的 webpack 配置修改掉

/** ----- next.config.js -----  */
module.exports = withMDX({webpack(config, nextConfig) {// add less compileconfig = injectLessLoader(config, nextConfig);return config},
});/** ----- injectLessLoader.js -----  */
const get = require('lodash/get');
const cloneDeep = require('lodash/cloneDeep');const addLessToRegExp = (rx) =>new RegExp(rx.source.replace("|sass", "|sass|less"), rx.flags);const injectLessLoader = (config, nextConfig) => {let sassModuleRule;// 1. 找到处理样式的 ruleconst cssRule = config.module.rules.find((rule) => get(rule, 'oneOf[0].options.__next_css_remove'));cssRule.oneOf.forEach((rule) => {if (get(rule, 'use.loader') === "error-loader") return;// 2. 增加 file-loader 处理 less 中资源的能力if ((get(rule, 'use.loader') || []).includes("file-loader")) {rule.issuer = Array.isArray(rule.issuer)? rule.issuer.map(rx => addLessToRegExp(rx)): addLessToRegExp(rule.issuer);}// 3. 筛选出 sass 的处理 ruleif (get(rule, 'test.source') === "\\.module\\.(scss|sass)$") {sassModuleRule = rule;}});// 4. less 的处理是在拷贝的 sass 的处理基础上修修改改得到的let lessRule = cloneDeep(sassModuleRule);lessRule.test = /\.less$/;// 删除 issuer 对文件目录的限制delete lessRule.issuer;// 替换 sass-loader 为 less-loaderlessRule.use.splice(-1, 1, {loader: "less-loader",options: {lessOptions: {javascriptEnabled: true,globalVars: {ASSET_PATH: get(nextConfig, 'config.env.ASSET_PATH') || '/'}}},});// 重要:将 sideEffects 设置为 true 否则非 css-module 不会被打包lessRule.sideEffects = true;// 更改 css-loader 的配置const cssLoaderInLessModuleIndex = lessRule.use.findIndex((item) =>`${item.loader}`.includes('css-loader'),);const cssLoaderInLessModule = lessRule.use.find((item) =>`${item.loader}`.includes('css-loader'),);// cloneconst cssLoaderClone = cloneDeep(cssLoaderInLessModule);// 去除 getLocalIdent,改为使用 localIdentNameif (get(cssLoaderClone, 'options.modules.getLocalIdent')) {delete cssLoaderClone.options.modules.getLocalIdent;}// 更新 css-loader 主要更新 modules 配置cssLoaderClone.options = {...cssLoaderClone.options,sourceMap: Boolean(nextConfig.dev),modules: {localIdentName: '[local]--[hash:4]',...cssLoaderClone.options.modules,mode: 'local',auto: true, // 自动识别是不是 css-module}}// 5. 将定制后 less 处理插入到 webpack 配置中lessRule.use.splice(cssLoaderInLessModuleIndex, 1, cssLoaderClone);cssRule.oneOf.splice(cssRule.oneOf.indexOf(sassModuleRule), 0, lessRule);return config;
}module.exports = injectLessLoader;

通过如上的配置,我们就可以安全的在 项目中使用 less 了,默认导入的 less 都是 global 的,如果想要适用 css-module 请给文件命名为 xxx.module.less

5. 定义 webpack alias

由于整个组件库项目使用的时 monorepo 结构,因此组件的实现代码在另外一个 子包中,要想在 文档项目 中方便的使用另外一个 package 中的组件,需要我们做如下的配置

/** ----- next.config.js -----  */
module.exports = withMDX({webpack(config, nextConfig) {// add less compileconfig = injectLessLoader(config, nextConfig);// add aliasconfig = injectAlias(config);return config},
});/** ----- injectAlias.js -----  */
const path = require('path');const injectAlias = (config) => {config.resolve.alias = {...config.resolve.alias,'~controls': path.resolve(__dirname, './src/controls'),'~docs': path.resolve(__dirname, './docs'),"@mjz-test/mjz-ui": path.resolve(__dirname, "../../../mjz-ui/src"), // 配置去获取源文件, 这样可以通过解析拿到组件的 TS 类型"@mjz-test/icons": path.resolve(__dirname, "../../../icons/src"),}return config;
}module.exports = injectAlias;/** ----- tsconfig.json -----  */
{"compilerOptions": {//..."paths": { // 配置路径,使得 TS 可以识别"~controls": ["./src/controls/index.tsx"],"~docs/*": ["./docs/*"],"@mjz-test/mjz-ui": ["../mjz-ui/src/index.tsx"],"@mjz-test/icons": ["../icons/src/index.tsx"]}},"include": ["next-env.d.ts","src","docs","typings","../mjz-ui/src", // 加入解析"../icons/src"],
}

经过上阶段的配置虽然可以在项目中使用 mdx 语法 来创建页面了

基于 next.js + mdx 搭建组件库文档项目(一) -- 开发环境搭建相关推荐

  1. 基于 next.js + mdx 搭建组件库文档项目(二) -- mdx 控件封装实现组件的演示与 Props 列表

    说明 经过上阶段的配置虽然可以在项目中使用 mdx 语法 来创建页面了,但是我们的组件库有一些定制化的需求:交互式的组件演示.组件 Props 列表展示.这些功能如果可以通过封装来实现,会大大提升开发 ...

  2. 【技术文档】Jeecg-P3开发环境搭建入门(java插件开发框架)

    一.项目工程说明 jeecg-p3-web       | 启动主项目 jeecg-p3-biz-demo | 插件项目     注意:项目为maven工程,采用maven方式导入eclipse等ID ...

  3. vue手机端项目php,MintUI基于Vue.js移动端组件库详解

    Mint UI 包含丰富的 CSS 和 JS 组件,能够满足日常的移动端开发需要.接下来通过本文给大家分享Mint UI 基于 Vue.js 移动端组件库,需要的朋友参考下吧,希望能帮助到大家. 官网 ...

  4. 使用VitePress静态网站生成器创建组件库文档网站并部署到GitHub

    Vue3+TS+Vite开发组件库并发布到npm 网站在线预览: Vue Amazing UI | Amazing UI Components LibraryAmazing UI 组件库https:/ ...

  5. StoryBook 开发React组件库文档

    StoryBook 开发 React 组件库文档 说明 StoryBook 是一个开源的 UI 组件库构建工具,支持 React.Vue.Angular 等主流开发框架,使用 StoryBook 将获 ...

  6. Docker java项目发布/开发环境搭建

    Docker java项目发布/开发环境搭建 线上部署项目/开发环境搭建命令大全 关闭windows10 指定应用 安装Docker 安装 docker-compose 关于docker容器导致硬盘耗 ...

  7. 组件库系列三:编写组件库文档

    文章目录 vuepress介绍 创建文档工程 配置运行指令 vuepress浏览器自动更新 下载插件和依赖 npm/yarn link docs文件夹 .vuepress文件夹 可收缩代码块 效果展示 ...

  8. 好文分享:Javaweb开发环境搭建常用工具类型

    随着互联网的不断发展,无论是前端开发还是后端开发都越发垂直细分化,而今天我们就通过案例分析来了解一下,Javaweb开发环境搭建常用工具类型. 一:Web相关概念 Web程序也就是一般所说的网站,由服 ...

  9. linux php环境搭建_PHP-小程序:(1)开发环境搭建

    很久之前就有计划搭建个私人用的听书小程序,利用周末时间,也零零散散的做了些准备,比如php.小程序.redis.linux相关知识的学习等,也记录了一些学习心得到今日头条,但都比较零散,不够系统清晰. ...

最新文章

  1. php lwm2m,理解COAP/LWM2M/MQTT协议和TCP/UDP协议的关系
  2. matlab 机械动力学仿真,基于MATLAB的机器人动力学仿真与控制.PDF
  3. [原创]浅析汇编之堆栈平衡
  4. 使用示波器测量运放带宽和压摆率
  5. 05、汇编语言和汇编软件
  6. java web 徐林林_零点起飞学Java Web开发 (徐林林) 高清PDF
  7. 移动GIS开发:手机基站定位+离线切片地图(矢量vtpk+栅格tpk)导航安卓APP
  8. mui获取手机设备信息
  9. Excel之VLookup函数
  10. java-php-python-爱心公益网站设计与制作计算机毕业设计
  11. Python 3 怎么快速搭建服务器
  12. 康旅江湖,谁在编写琅琊榜
  13. Shader——漩涡效果
  14. C/语/言/自/学/笔记
  15. 36V转24V转20V转15V转12V转9V降压电源芯片众多型号
  16. 正准备换工作的你需要注意哪些面试细节
  17. vant 组件van-tabbar实现底部导航
  18. 音频信号处理库librosa
  19. mysql视图和中间表_数据库设计中的14个技巧
  20. avc水平什么意思_avc是什么意思 什么是avc

热门文章

  1. 虫食算-详解-noip2004-深搜
  2. 提交apk到小米应用商店,monkey测试未通过被拒
  3. IDaaS 服务的三大场景 B2E/B2C/B2B
  4. 关于聚类算法Kmeans/K-mediods/层次聚类/OPTICS较为详细的介绍
  5. 初始Android动画
  6. 电力电子技术复习笔记2
  7. 如何打造元宇宙NFT头像?教你玩点新鲜的!
  8. 软件测试做了五年黑盒测试,我总结的这些经验
  9. 关于Vue的MVVM
  10. 产品的发展趋势—让人类充满幸福感的产品