pnpm(2)创建hooks 发布静态站点到github.io站点

133 阅读2分钟

创建一个hooks

menus 需要消费packages/hooks底下的内容 

packages/hooks/src 下新建useToggle 文件夹 index 文件

自定义hooks

import {useMemo, useState} from 'react'type defultFn = () =>void;export interface Actions{    setLeft:defultFn;    setRight:defultFn;    toggle:defultFn;}function useToggle<T = boolean>():[boolean,Actions];//返回结构为DRfunction useToggle<D,R>(defaultValue:D = false as D ,reversevalue?:R){    const [state,setState] = useState<D | R>(defaultValue);    const actions = useMemo(()=>{        const reversevalueOrigin = (reversevalue === undefined ? !defaultValue : reversevalue) as D|R;        const toggle = () =>setState((s) => (s === defaultValue ? reversevalueOrigin : defaultValue));        const setLeft = () =>setState(defaultValue);        const setRight = () =>setState(reversevalueOrigin);        return {            toggle,            setLeft,            setRight        }    },[])    return [state, actions];}export default useToggle

src index.ts 中引入导出

import useToggle from "./useToggle";export{    useToggle}

最外层config.ts中配置

      "paths": {        "@/*": ["src/*"],        "demoHook": ["./packages/hooks/src/index.ts"],//配置相应的映射        "demo-hooks": ["./packages/hooks/src/index.ts"],        "encodeHooks/lib/*": ["./packages/hooks/src/*"],        "encode-hooks/lib/*": ["./packages/hooks/src/*"]      },

useToggle 下创建对应demo文件夹 demo1.tsx

/** * title:useToggle基础用法 * desc:当action中的值没有初始化时,默认是false */import React from "react";import {useToggle} from 'demoHook';export default ()=>{    const [state,{toggle,setLeft,setRight}] = useToggle();    return <div>        <p>当前state 的值为:{`${state}`}</p>        <p>            <button type ="button" onClick={toggle}>toggle切换</button>        </p>        <p>            <button type ="button" onClick={setLeft}>setLeft切换</button>        </p>        <p>            <button type ="button" onClick={setRight}>setRight切换</button>        </p>    </div>}

useToggle下创建index.md  path 关联/hooks 路径

---nav:  path: /hooks---# useToggle进行值切换的基础 hooks## demo<code src="./demo/demo1.tsx">

menus 中消费相应的index.md

export const menus = [    {      title: '状态',      children: ['useToggle'],    },  ];

config.ts中配置

alias: {      demoHook: process.cwd() + '/packages/hooks/src/index.ts',    },
 //导航栏的配置    navs: [      { title: '指南', path: '/guide' },      { title: 'Hooks', path: '/hooks' },    ],    //指向的docs文件夹下的路径,默认Index    menus: {      '/': [        {          title: '首页',          path: 'index',        },      ],      '/guide': [        {          title: '介绍', // 左侧导航栏内容          path: '/guide',        },      ],      '/hooks': menus,    },

jest 写测试用例

全局状态下配置jest.config.js
//针对浏览器黄精配置的基础jest 内容module.exports = {    preset: 'ts-jest/presets/js-with-ts',    testEnvironment: 'jsdom',    clearMocks: true,    testPathIgnorePatterns: ['/.history/'],    modulePathIgnorePatterns: ['<rootDir>/package.json'],    resetMocks: false,    setupFiles: ['./jest.setup.js', 'jest-localstorage-mock'],    setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],    transform: {      '^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.json' }],    },    moduleNameMapper: {      '^lodash-es$': 'lodash',    },    collectCoverageFrom: [      '<rootDir>/**/src/**/*.{js,jsx,ts,tsx}',      '!**/demo/**',      '!**/example/**',      '!**/es/**',      '!**/lib/**',      '!**/dist/**',    ],    transformIgnorePatterns: ['^.+\\.js$'],  };

创建一个空的 jest.setup.js,存放一些公共的方法

jest 默认会解析_tests_下的文件 index.test.ts

import {renderHook,act} from '@testing-library/react'import useToggle from "../index";const callToggle = (hook)=>{    act(()=>{        hook.result.current[1].toggle()    })}describe('useToggle',()=>{    //jest    it('针对基础功能使用测试',()=>{        const hooks = renderHook(()=>useToggle());        expect(hooks.result.current[0]).toBe(false);    })    it('针对手动切换toggle模拟',()=>{        const hooks = renderHook(()=> useToggle("haleyliang","lianghaley"))        expect(hooks.result.current[0]).toBe("haleyliang");        callToggle(hooks)        expect(hooks.result.current[0]).toBe("lianghaley");    })})

package.json 

scripts
    "test":"jest"

pnpm run test 运行测试用例 或者指名道姓执行一个单一的测试用例 

pnpm run test useToggle

npm 代码构建发布

全局package.json中添加指令

"pub:beta":"pnpm run build && pnpm -r --filter=./packages/hooks publish --tag beta",
"pub":"pnpm run build && pnpm -r --filter=./packages/hooks publish",
"build:doc": "dumi build",

登录npm

执行 pnpm run pub:beta  发布包 仅可用于首次
pnpm run pub 发布包第二次同时需要修改包版本

发布成功,npm packages 下可以查到发布的包

外层添加 README.md , gulp打包同步README.md 到 hooks文件夹下

gulp.task('copyReadme', async function () {  await gulp.src('../../README.md').pipe(gulp.dest('../../packages/hooks'));});
package.json 中添加待发布包文件路径
"files": ["README.md"]

README.md 最终就是npm 包的描述

收集meta信息

hooks gulpfile.js  md 下的标题通过正则校验添加至meta.json 文件中,并发布至npm

const commonConfig =  require('../../gulpfile');const gulp = require('gulp');const fs = require('fs');const fse = require('fs-extra');const fg = require("fast-glob");//类似于fs的升级版const gm = require('gray-matter');const { async } = require('fast-glob');async function genDesc(mdPath){    if(!fs.existsSync(mdPath)){        return    }    const mdFile = fs.readFileSync(mdPath,'utf-8');    const {content} = gm(mdFile);    let description =    (content.replace(/\r\n/g, '\n').match(/# \w+[\s\n]+(.+?)(?:, |\. |\n|\.\n)/m) || [])[1] || '';    description = description.trim();    return description}    //添加一个hooks的文档声明async function genMetaData(){    //收集meta描述    const metaData={        function:[]    };    //获取srcuse* 目录名,map循环遍历去除src/路径前缀,排序    const hooks = fg.sync('src/use*',{        onlyDirectories:true    }).map((hooks)=>hooks.replace('src/','')).sort();    // console.log(hooks) [ 'useToggle' ]    await Promise.allSettled(        hooks.map(async (hook)=>{            const description = await genDesc(`src/${hook}/index.md`);            return {                name:hook,                description            }        }).then((res)=>{            metaData.function = res.map((item)=>{                if(item.status === 'fulfilled'){                    return item.value                }                return null            })        })    )    return metadata;}gulp.task('metaData', async function(){    const metaData = await genMetaData();    await fse.writeJson('metadata.json', metadata, { spaces: 2 });})exports.default = gulp.series(commonConfig.default,'metaData');

发布代码到github.io, 创建  .github/workflows  包含test.yml deploy.yml

可参照 使用Github Actions 来构建发布应用 - 知乎 (zhihu.com)

test.yml

name: Build and Deployon:  push:    branches:      - masterjobs:  build-and-deploy:    runs-on: ubuntu-latest    steps:      - name: Checkout  ️        uses: actions/checkout@v2.3.1      - name: lock npm version        uses: actions/setup-node@v3        with:          node-version: 16.18.0      - name: Install and Build        run: |          npm i -g pnpm          pnpm run init        env:          NODE_OPTIONS: '--max_old_space_size=4096'      - name: test        run: |          pnpm run test

deploy.yml

name: Build and Deployon:  push:    branches:      - masterjobs:  build-and-deploy:    runs-on: ubuntu-latest    permissions:      contents: write    steps:      - name: Checkout        uses: actions/checkout@v2.3.1      - name: Lock npm version        uses: actions/setup-node@v3        with:          node-version: 16.18.0      - name: Install and Build        run: |          npm i -g pnpm          pnpm run init          pnpm run build:doc        env:          NODE_OPTIONS: '--max_old_space_size=4096'      - name: Deploy        uses: JamesIves/github-pages-deploy-action@4.1.3        with:          BRANCH: gh-pages          FOLDER: dist          ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}

ACCESS_TOKEN是访问github api的令牌

点击github主页 --- 个人头像 -- settings --- develper settings --- Personal access tokens 进行生成  ACCESS_TOKEN

配置 ACCESS_TOKEN

配置路径

若页面能正常打开但是js css 请求报404则配置如下路径