likes
comments
collection
share

还不会发包?30S教会你

作者站长头像
站长
· 阅读数 37

前言

学会发包可以避免我们在项目开发中重复造轮子的现象;当我们开发了通用的组件或者工具库后可以将其发布到npm上,这样在我们后续有同样需求的时候就可以直接下载下来用了,是不是灰常的的灵性。不知道怎么发包的小伙伴可以跟着我从0到1的发布一个包(发包流程跟技术框架和打包工具没有必然的联系,可根据自身情况进行技术选型)

技术栈

操作流程

1. 准备项目工程并编写组件

  1. 创建一个基础模板(这里我通过vite创建一个react模板,node版本要求:14.18+,16+ )
npm: npm create vite@latest

or

yarn: yarn create vite

然后根据命令行提示输入项目名称、选择框架、选择语言 我这边选择的是:ReactTypeScript

  1. 项目创建后先安装依赖
npm: npm install
npm: npm install less less-loader -D

or

yarn: yarn
yarn: yarn add less less-loader -D
  1. 改造模板(可根据个人习惯改造)
  • 删除样式文件App.cssindex.css
  • assets目录创建styles目录用于存放样式
  • /assets/styles新建index.less文件,所有样式都统一从这里导出
  • src目录下新建components目录用于编写组件
  • /src/components目录下新建index.ts文件,所有组件都统一从这里导出
  • 跟目录下新建index.d.ts类型文件
  • 改造main.tsx
  • 改造App.tsx

类型文件index.d.ts

import { ReactNode } from "react"

export declare type XButtonType = {
    children: string | ReactNode
    primaryColor?: string
    onClick?: () => void
}

main.tsx 改造后

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
// 引入项目所需样式
import './assets/styles/index.less'
// 导出组件
export * from './components/index'

const mode = import.meta.env.MODE

if (mode !== 'production') {
  // <App /> 组件里面可以放我们的组件测试代码 所以开发环境这一步是必要的
  // 但是生产环境渲染节点会显得多余 所以生产环境不需要这一步(主要是react18+ createRoot不能使用多次,否则开发者使用该包时控制台会报警告)
  ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
    <App />
  )
}

App.tsx 改造后

import { XButton } from "./components"

function App() {
  return (
    <div className="App">
      <XButton>测试</XButton>
    </div>
  )
}

export default App

献上我的组件 components/XButton.tsx

import React from "react";
import { XButtonType } from "../..";

// 组件很简单 就是一个可以动态改变颜色和内容的按钮
export default function XButton(props: XButtonType) {
  const { children, primaryColor = "#8f0ce7", onClick } = props;
  const style: React.CSSProperties = {
    "--x-primary-color": primaryColor,
  } as React.CSSProperties;
  return (
    <button className="x-button" style={style} onClick={onClick}>
      {children}
    </button>
  );
}

** 注意点:使用index.d.ts文件需要在tsconfig.json文件中配置一下

"include": ["src"],
// 配置后
"include": ["src", "index.d.ts"],

2. 配置vite.config.ts

  1. 下载path
npm: npm install path -D

or

yarn: yarn add path -D
  1. 配置vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()]
  build: {
    lib: {
      // 打包入口
      entry: resolve('src', 'main.tsx'),
      name: 'x-button',
      // 文件名称
      fileName: 'index',
    },
    rollupOptions: {
      // 确保外部化处理那些你不想打包进库的依赖
      external: ['react', 'react-dom'],
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
            react: 'React',
        },
      },
    },
    // 打包输出目录
    outDir: 'lib/dist', 
  },
})
  1. 执行打包命令
npm: npm run build

or 

yarn: yarn build
  1. 根目录会生成一个lib目录,这时打包工作已经完成,不过还有几个坑我们后面来填

3. 配置npm

  1. 终端执行命令
npm init
  1. 根据命令行提示输入对应信息
  • package name: 包名,发到npm上的名称
  • version: 版本号
  • description:项目描述(选填)
  • entry point: 入口文件路径(路径就是我们打包后的目录文件 ./lib/dist/index.js)
  • git repository:仓库地址(选填)
  • keywords: 关键词(选填)
  • author:作者信息(选填)
  • license:开源协议(默认ISC,关于开源协议可以自行了解)
  1. 修改package.json部分配置
{
  "name": "xz-test-button",
  "private": false, // true改为false
  "version": "0.0.1",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.22",
    "@types/react-dom": "^18.0.7",
    "@vitejs/plugin-react": "^2.2.0",
    "less": "^4.1.3",
    "less-loader": "^11.1.0",
    "path": "^0.12.7",
    "typescript": "^4.6.4",
    "vite": "^3.2.2"
  },
  "types": "./index.d.ts",
  "description": "按钮",
  "main": "./lib/dist/index.js",
  // 新增 ----------->----------->
  "module": "./lib/dist/index.js",
  "exports": {
    ".": {
      "import": "./lib/dist/index.js",
      "require": "./lib/dist/index.umd.cjs"
    }
  },
  "files": [
    "lib",
    "index.d.ts"
  ],
  // <--------------<------------
  "author": "",
  "license": "ISC"
}

经过上面操作我们的准备工作已经完成

4. 发布

  1. 没有npm账号的可以先去npm官网注册一个或者通过npm adduser命令注册
  2. 完成上面步骤后我们先登录npm账号,执行npm login命令进行登录,根据命令行提示输入用户名、密码、邮箱、邮箱验证码
  3. 登录完成后我们执行npm publish命令进行发布
    • 这里发包可能会出现404或者403,这时先确保是否登录成功,然后再确认当前项目名称是否和npm已有的包冲突,更换名字后再进行尝试
    • 每次发包需要保证当前版本号在此之前没有被使用(发布)过
  4. 当终端没有报错且最后一行显示包名和版本号就表示发布成功
    • xz-test-button@0.0.1
    • 可以去npm官网去搜索自己的包名或者在自己的包列表查看
  5. 完成以上操作后一个npm包就算是发布成功了,但是还没完...

5. 使用

  1. 在另一个项目中npm install 包名或者yarn add 包名
  2. 使用方式
import { XButton } from "xz-test-button";

function App() {
  return (
    <div className="App">
      <XButton>测试</XButton>
    </div>
  );
}

export default App;
  1. 使用中的问题:
  • 样式没加载 还不会发包?30S教会你
  • 使用问题:类型问题 还不会发包?30S教会你

6. 填坑

虽然包发布成功了,但是前面说过还有一些坑需要填,这些坑刚刚也看见了,都是在使用的时候出现的

  1. 样式问题
  • 将包下载到另一个项目使用会发现组件结构是存在的就是没有样式,这是因为vite打包的时候虽然将样式打包到输出目录了,但是在js文件中没有引用css文件;
  • 解决方案:
    • 可以手动将style.css引入到index.js中(每次打包都需要引一次,比较麻烦,不推荐)
    • 通过vite-plugin-libcss插件自动引入(推荐),先下载依赖:
npm: npm install vite-plugin-libcss -D

or 

yarn: yarn add vite-plugin-libcss -D

改造vite.config.ts文件

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
import libCss from 'vite-plugin-libcss';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), libCss()],
  ... 不变 ...
})
  1. 问题:模块“"xxx"”没有导出的成员“x”或者找不到“xxx”的类型声明文件
  • 因为项目是TypeScript开发的所以我们需要模块导出,通过改造index.d.ts文件来解决
import React, { ReactNode } from "react"

export declare type XButtonType = {
    children: string | ReactNode
    primaryColor?: string
    onClick?: () => void
}

declare module 'xz-test-button' {
    export function XButton(props: XButtonType): JSX.Element
}

然后重新打包即可

7. 更新包

  1. 首先更新包版本npm version patch(因为我们是修复bug,所以我们只需更新修复版本号)
  2. 再次执行发包命令npm publish
  3. 最后在使用这个包的项目中重新下载一次这个包就不会出现类型问题和样式问题了

总结

通过上面一套流程走下来会发现其实发包很简单,也就是执行一些命令,修改一些配置就能完成;可能难点就是针对一些细节问题,比如发包404、403、401、组件样式问题、TS类型问题。能处理好这些细节就基本没什么问题了