基于 next.js + mdx 搭建组件库文档项目(一) -- 开发环境搭建
说明
之前使用过 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 配置、服务器配置等等问题上,只要专注于业务开发就可以了
优点
- 基本上不需要配置,模块打包、编译、优化等都不需要考虑
- 基于文件系统的路由,每个 pages 目录下的文件都是一个路由(有的时候可能不够灵活)
- 支持 SSG(静态站点生成) 和 SSR(服务器端渲染)
- 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 搭建组件库文档项目(一) -- 开发环境搭建相关推荐
- 基于 next.js + mdx 搭建组件库文档项目(二) -- mdx 控件封装实现组件的演示与 Props 列表
说明 经过上阶段的配置虽然可以在项目中使用 mdx 语法 来创建页面了,但是我们的组件库有一些定制化的需求:交互式的组件演示.组件 Props 列表展示.这些功能如果可以通过封装来实现,会大大提升开发 ...
- 【技术文档】Jeecg-P3开发环境搭建入门(java插件开发框架)
一.项目工程说明 jeecg-p3-web | 启动主项目 jeecg-p3-biz-demo | 插件项目 注意:项目为maven工程,采用maven方式导入eclipse等ID ...
- vue手机端项目php,MintUI基于Vue.js移动端组件库详解
Mint UI 包含丰富的 CSS 和 JS 组件,能够满足日常的移动端开发需要.接下来通过本文给大家分享Mint UI 基于 Vue.js 移动端组件库,需要的朋友参考下吧,希望能帮助到大家. 官网 ...
- 使用VitePress静态网站生成器创建组件库文档网站并部署到GitHub
Vue3+TS+Vite开发组件库并发布到npm 网站在线预览: Vue Amazing UI | Amazing UI Components LibraryAmazing UI 组件库https:/ ...
- StoryBook 开发React组件库文档
StoryBook 开发 React 组件库文档 说明 StoryBook 是一个开源的 UI 组件库构建工具,支持 React.Vue.Angular 等主流开发框架,使用 StoryBook 将获 ...
- Docker java项目发布/开发环境搭建
Docker java项目发布/开发环境搭建 线上部署项目/开发环境搭建命令大全 关闭windows10 指定应用 安装Docker 安装 docker-compose 关于docker容器导致硬盘耗 ...
- 组件库系列三:编写组件库文档
文章目录 vuepress介绍 创建文档工程 配置运行指令 vuepress浏览器自动更新 下载插件和依赖 npm/yarn link docs文件夹 .vuepress文件夹 可收缩代码块 效果展示 ...
- 好文分享:Javaweb开发环境搭建常用工具类型
随着互联网的不断发展,无论是前端开发还是后端开发都越发垂直细分化,而今天我们就通过案例分析来了解一下,Javaweb开发环境搭建常用工具类型. 一:Web相关概念 Web程序也就是一般所说的网站,由服 ...
- linux php环境搭建_PHP-小程序:(1)开发环境搭建
很久之前就有计划搭建个私人用的听书小程序,利用周末时间,也零零散散的做了些准备,比如php.小程序.redis.linux相关知识的学习等,也记录了一些学习心得到今日头条,但都比较零散,不够系统清晰. ...
最新文章
- php lwm2m,理解COAP/LWM2M/MQTT协议和TCP/UDP协议的关系
- matlab 机械动力学仿真,基于MATLAB的机器人动力学仿真与控制.PDF
- [原创]浅析汇编之堆栈平衡
- 使用示波器测量运放带宽和压摆率
- 05、汇编语言和汇编软件
- java web 徐林林_零点起飞学Java Web开发 (徐林林) 高清PDF
- 移动GIS开发:手机基站定位+离线切片地图(矢量vtpk+栅格tpk)导航安卓APP
- mui获取手机设备信息
- Excel之VLookup函数
- java-php-python-爱心公益网站设计与制作计算机毕业设计
- Python 3 怎么快速搭建服务器
- 康旅江湖,谁在编写琅琊榜
- Shader——漩涡效果
- C/语/言/自/学/笔记
- 36V转24V转20V转15V转12V转9V降压电源芯片众多型号
- 正准备换工作的你需要注意哪些面试细节
- vant 组件van-tabbar实现底部导航
- 音频信号处理库librosa
- mysql视图和中间表_数据库设计中的14个技巧
- avc水平什么意思_avc是什么意思 什么是avc