返回

掌握技术细节,0️搭建、开发和发布一个 npm 包(React + Webpack + TypeScript + Less)

前端

前言

在前端开发中,我们经常需要复用一些通用组件或工具。为了方便管理和共享,我们可以将这些组件或工具打包成 NPM 包。NPM 是一个流行的 JavaScript 包管理工具,它允许开发者轻松地安装、管理和发布 JavaScript 包。

本文将详细介绍如何从零开始搭建、开发和发布一个 NPM 包,涵盖技术选型、项目结构、开发环境搭建、组件开发、单元测试、代码规范、性能优化、组件库构建和发布到 NPM 的整个过程。旨在帮助开发者掌握构建 NPM 包的完整流程,提高前端开发技能。

技术选型

在搭建 NPM 包之前,我们需要选择合适的技术栈。本文将使用以下技术:

  • React:一个用于构建用户界面的 JavaScript 库。
  • Webpack:一个用于打包 JavaScript 模块的工具。
  • TypeScript:一种对 JavaScript 的超集,可以提供更好的类型检查和代码重构。
  • Less:一种 CSS 预处理器,可以帮助我们更轻松地编写 CSS 代码。

项目结构

一个典型的 NPM 包的项目结构如下:

├── package.json
├── src/
│   ├── index.tsx
│   ├── components/
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   └── ...
│   ├── styles/
│   │   ├── main.less
│   │   └── ...
├── test/
│   ├── index.test.tsx
│   ├── components/
│   │   ├── Button.test.tsx
│   │   ├── Input.test.tsx
│   │   └── ...
├── webpack.config.js
└── README.md
  • package.json:包含项目的基本信息,如名称、版本、依赖项等。
  • src/:包含源代码。
  • test/:包含单元测试代码。
  • webpack.config.js:Webpack 配置文件。
  • README.md:项目说明文档。

开发环境搭建

首先,我们需要安装必要的开发工具。

npm install -g create-react-app

然后,创建一个新的 React 项目。

create-react-app my-npm-package

这将创建一个新的 React 项目,并安装必要的依赖项。

接下来,我们需要安装 TypeScript 和 Less。

npm install --save-dev typescript less less-loader

然后,我们需要在 tsconfig.json 文件中启用 TypeScript。

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "jsx": "react",
    "allowSyntheticDefaultImports": true
  }
}

最后,我们需要在 webpack.config.js 文件中配置 TypeScript 和 Less。

const path = require('path');
const webpack = require('webpack');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');

module.exports = {
  entry: './src/index.tsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'index.js',
    libraryTarget: 'umd',
    library: 'MyNpmPackage',
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    plugins: [
      new TsconfigPathsPlugin({
        configFile: './tsconfig.json',
      }),
    ],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'less-loader',
        ],
      },
    ],
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
    }),
  ],
};

组件开发

接下来,我们可以开始开发组件了。我们将创建一个简单的按钮组件。

import React from 'react';
import styles from './Button.module.less';

const Button = ({ children, ...props }) => {
  return (
    <button {...props} className={styles.button}>
      {children}
    </button>
  );
};

export default Button;
.button {
  padding: 10px 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
  background-color: #fff;
  color: #000;
  cursor: pointer;
}

.button:hover {
  background-color: #eee;
}

.button:active {
  background-color: #ccc;
}

单元测试

为了确保组件的正确性,我们需要编写单元测试。

import React from 'react';
import { shallow } from 'enzyme';
import Button from './Button';

describe('Button', () => {
  it('should render correctly', () => {
    const wrapper = shallow(<Button>Hello World</Button>);

    expect(wrapper).toMatchSnapshot();
  });

  it('should call onClick prop when clicked', () => {
    const onClick = jest.fn();
    const wrapper = shallow(<Button onClick={onClick}>Hello World</Button>);

    wrapper.find('button').simulate('click');

    expect(onClick).toHaveBeenCalledTimes(1);
  });
});

代码规范

为了保持代码的一致性和可读性,我们需要制定代码规范。我们使用 Prettier 来格式化代码。

npm install --save-dev prettier

然后,在 .prettierrc 文件中配置 Prettier。

{
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100,
  "tabWidth": 2,
  "semi": true,
  "endOfLine": "auto"
}

最后,我们在 package.json 文件中添加一个 scripts 字段。

"scripts": {
  "start": "webpack-dev-server --open",
  "build": "webpack --mode production",
  "test": "jest",
  "lint": "prettier --check 'src/**/*.{ts,tsx,js,jsx,less}'",
  "format": "prettier --write 'src/**/*.{ts,tsx,js,jsx,less}'"
}

这样,我们就可以使用 npm run lint 来检查代码是否符合代码规范,使用 npm run format 来格式化代码。

性能优化

为了提高组件的性能,我们可以使用以下技术:

  • 代码拆分:将组件的代码拆分成多个小的代码块,以便按需加载。
  • 懒加载:只在需要时加载组件。
  • 缓存:将组件的输出结果缓存起来,以便下次加载时可以重用。

我们可以使用 Webpack 来实现代码拆分和懒加载。

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  // ...
  plugins: [
    new webpack.DllReferencePlugin({
      context: path.join(__dirname, 'src'),
      manifest: path.join(__dirname, 'dll', 'manifest.json'),
    }),
    // ...
  ],
};
// src/index.tsx
import React, { lazy } from 'react';

const Button = lazy(() => import('./Button'));

const App = () => {
  return (
    <div>
      <Button />
    </div>
  );
};

export default App;

我们还可以在组件中使用 useMemouseCallback 来进行缓存。

import React, { useMemo, useCallback } from 'react';

const Button = ({ onClick }) => {
  const handleClick = useMemo(() => {
    return () => {
      onClick();
    };
  }, [onClick]);

  return (
    <button onClick={handleClick}>Click Me</button>
  );
};

export default Button;

组件库构建

接下来,我们需要将组件库构建成一个 NPM 包。

npm run build

这将在 dist 文件夹中生成一个 index.js