您现在的位置是:主页 > news > 腾讯云网站备案靠谱吗/漯河seo公司

腾讯云网站备案靠谱吗/漯河seo公司

admin2025/6/27 10:04:15news

简介腾讯云网站备案靠谱吗,漯河seo公司,个人简介代码网页制作模板,公司做公司网站广告前言 随着企业内部开发的项目逐渐增多,组件的维护工作变得愈益困难. 前端同学通常会面临的困境之一.开发完了A项目,在A项目下封装了大量的公共组件.当B项目启动时,由于设计风格相似,以至于A项目的很多组件可以直接复制到B项目下使用. A和B项目开发完毕,后续的C和D项目又启动…

腾讯云网站备案靠谱吗,漯河seo公司,个人简介代码网页制作模板,公司做公司网站广告前言 随着企业内部开发的项目逐渐增多,组件的维护工作变得愈益困难. 前端同学通常会面临的困境之一.开发完了A项目,在A项目下封装了大量的公共组件.当B项目启动时,由于设计风格相似,以至于A项目的很多组件可以直接复制到B项目下使用. A和B项目开发完毕,后续的C和D项目又启动…

前言

随着企业内部开发的项目逐渐增多,组件的维护工作变得愈益困难.

前端同学通常会面临的困境之一.开发完了A项目,在A项目下封装了大量的公共组件.当B项目启动时,由于设计风格相似,以至于A项目的很多组件可以直接复制到B项目下使用.

AB项目开发完毕,后续的CD项目又启动.每当有新项目启动时,手工复制就要重复一遍,这样的工作不仅乏味而且低效.

如果仅仅只是在新项目启动时,将旧项目的组件代码复制一遍还能勉强接受.

倘若有一天,产品经理要求D项目下的某个公共组件做一下样式的调整,并且ABC项目下的对应的公共组件同步更新,那么这样的机械劳动会随着项目数量的增多变得无休无止.

本文以企业已产出的项目为视角,将之前开发好的react组件抽离出来封装成业务型组件库,而不是打造一款通用型的组件库,抽离出来的业务型组件库和通用型组件库有哪些区别呢?

  • 我们打造的组件库以业务组件为主,服务的对象是企业内部.因而我们开发的组件库可能会包含很多业务图片,比如公司的logo.
  • 一般而言,通用型组件库的所有组件都从0实现.但业务型组件不一样,它很多功能都是依赖于第三方组件库(比如antdElement UI)做的二次开发.因此业务型的组件库很可能集成了第三方组件库依赖.

源代码在文章末尾,可下载启动运行.

实现

项目搭建

首先本地搭建一个空项目,里面创建文件夹src/components,需要封装的组件都可以复制到components下面(如下图所示);

上图案例封装了四个组件,另外还单独创建了一个入口文件index.ts.

index.ts内部分别将components下的所有组件导入并暴露给外部调用.

// index.ts文件export { default as Button } from "./Button";export { default as Icon } from "./Icon";export { default as Logo } from "./Logo";export { default as Empty } from "./Empty";

我们看下components/Button组件的文件结构(如下图).

Button组件包含两个文件,一个是less样式文件,另一个是逻辑代码index.tsx.

Button组件的index.tsx内容很简单,它引入同级的less样式,并编写了组件逻辑,最后导出提供给外部使用.

import React from 'react';
import './index.less';type defaultProps = {text: string; //按钮的文案onClick?: any; //点击事件
};const Button = (props: defaultProps) => {return (<div onClick={props.onClick}>{props.text}</div>);
};export default Button;

文件结构介绍完毕,接下来编写webpack的配置文件将组件库代码打包输出(代码如下).

webpack配置文件的思路很简单,入口entry设置为组件库源代码src/components下对外暴露的入口文件index.ts,输出output设置成dist文件夹下.

rules里面主要处理tsxless文件.tsx文件是所有待封装组件的逻辑代码,因为组件的代码是使用ts语法编写的,因而先使用ts-loaderts语法转换后js,再使用babel去编译(具体配置细节可在源代码中查看).

less文件要先通过less-loaderless语法编译成css,再使用postcss使用插件给css加上满足各大浏览器兼容性的前缀.

postcss处理完传递给css-loader处理,最后使用MiniCssExtractPlugin插件将所有样式文件抽离出来放入app.css中.

// webpack.config.js文件const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");module.exports = {entry:path.resolve(__dirname,"src/components/index.ts"), //入口mode:"development",output: { //输出library: 'ui-design-demo',libraryTarget: 'umd',filename: 'bundle.js',path:path.resolve(__dirname,"dist")},resolve: {extensions: ['.tsx', '.ts', '.js'],},module:{rules: [{test: /\.tsx?$/,use: ['babel-loader','ts-loader'],exclude: /node_modules/,},{test: /\.(le|c)ss$/i,use: [{loader:MiniCssExtractPlugin.loader},{loader: "css-loader"},{loader: 'postcss-loader',options: {postcssOptions: {plugins: ['autoprefixer'],}},},// 将 less 编译成 CSS'less-loader'],}]}, plugins:[new MiniCssExtractPlugin({filename:"app.css"})]
};

webpack最终打包生成的文件如下图所示.所有组件的js代码都封装到bundle.js,而样式文件被单独抽离放入app.css.

如果将dist目录发布到npm仓库,其他项目该如何引入该组件库呢?

调试引入

为了让其他项目能够引入当前封装的组件库,首先要在组件库根目录下的package.json修改两个字段(如下图所示)

name是自定义组件库的名称,其他项目通过import或者require引入组件库中的组件时,name对应的就是被引入的组件库名称.

main设定了当前组件库的入口文件地址.

组件库的代码并不是开发完后就一成不变的,它可能随时会依据现实情况做出功能或样式的调整.

如果修改了组件库的代码,发布到npm仓库再让其他项目安装使用,过程过于繁琐.

npm link可以简化这一流程直接在本地调试组件库的代码.

本地桌面上重新创建一个新的react测试项目,完成以下三步可直接在测试项目中引入组件库.

  • 在组件库的根目录下执行npm link命令,将当前组件库链接到全局
  • 组件库的根目录下执行命令链接到测试项目下的react(不执行这一步可能会报错),比如npm link D:\react-ui-test\node_modules\react
  • 在测试项目react-ui-test根目录下,执行命令npm link ui-design-demo链接组件库,ui-design-demo就是上面定义的name

执行完上述三步后,测试项目就可以直接引入组件库中的组件进行测试了(代码如下).

// App.js 文件import React from "react";
import { Button } from "ui-design-demo";
import "ui-design-demo/dist/app.css";function App() {const clickEvent = () => {console.log(123);}return (<div className="App">Hello world<Button call="按钮" onClick={clickEvent}/></div>);
}export default App;

由于组件库的css代码被单独抽离成了app.css,因此测试项目想使用组件库一般要在项目入口文件index.js处将app.css给引入进来(上面代码为了方便看就在App组件引入了css).

测试项目启动后运行效果图如下.

有了npm link的赋能,组件库的调试变得容易.测试项目可以是临时创建的新项目,也可能是已经存在的真实项目.

它们都可以在本地直接启动引入组件库,如果发现组件库的组件有需要调整的地方,直接在组件库里修改编译,测试项目这边可以实时刷新观察效果.

图标处理

一般而言,组件内不可能只包含jscss.我们日常开发的很多组件都会用到图标,图标的用途主要有以下两方面.

  • 组件库内部的组件需要使用图标
  • 外部项目引用组件库时,需要使用组件库对外暴露的图标

为了同时满足上述两点要求,我们在组件库源代码src/components下新建一个组件Icon(如下图所示)

Icon下的less文件代码如下,直接引入从iconfont下载的字体图标样式.

// index.less文件
@import url('../../fonts/iconfont.css');

Icon下的index.tsx文件代码如下,封装了一个Icon组件提供给外部使用.

import React from 'react';
import './index.less';interface defaultProps {name:string;size?:number | string;
}const Icon = (props: defaultProps)=>{return <i className={`iconfont ${props.name}`} style={{fontSize:`${props.size?props.size:12}px`}}></i>;
}export default Icon;

紧接着源代码src/components下的入口文件index.ts要将Icon导出,最后修改一下webpack的配置文件.

配置文件webpack.config.js要在原来的基础添加上对字体文件的处理,配置完后打包生成的dist目录下会多出一个fonts文件夹,专门用来存放字体文件.

 // webpack.config.js 文件... //省略module:{rules: [...,{test:/\.(ttf|woff|woff2)$/,loader:"file-loader",options: {name: '[name].[ext]',outputPath: 'fonts'}}]}    ...

上述工作完成后,测试项目中可以直接引入字体图标进行使用,代码如下.

import React from "react";
import {Button,Icon} from "ui-design-demo";
import "ui-design-demo/dist/app.css";function App() {const clickEvent = () => {console.log(123);}return (<div className="App">Hello world<Button call="按钮" onClick={clickEvent}/><Icon name="icon-zengjia" size="50"/></div>);
}export default App;

效果图如下:

图片处理

组件库现在需要增加一个业务组件,用于展现公司的Logo,这时候需要组件库将图片集成进来.

组件库源代码src/components下新建组件Logo,文件结构如下图所示.

Logoindex.tsx和样式代码如下.类名为Logodiv需要展现一张图片,index.less使用背景图的方式引入了图片.

这里为什么不在index.tsx文件内直接使用import将图片引入进来?因为组件库使用webpack编译打包后图片路径发生了改变,测试项目引入该组件时可能会因为图片路径不对找不到图片.

less通过background加载背景图的方式可以避免图片路径出错的问题.

这是由于css在组件库中虽然被webpack编译了一次,但测试项目的入口文件会引入组件库全局css,那时测试项目的webpack还会对css编译一次,这样就保证了图片路径不会出错.

// index.tsx文件
import React from 'react';
import "./index.less";const Logo = () => {return (<div className="Logo"></div>);
};export default Logo;------------------------------------// index.less文件.Logo {width: 133px;height: 114px;background: url(../../images/logo.png) no-repeat;
}

另外webpack的配置文件需要增加对图片的处理(代码如下).

// webpack.config.js文件...module:{rules: [... // 省略{test:/\.(gif|jpg|png)$/,loader:"file-loader",options: {name: '[name].[ext]',outputPath: 'images'}}...]}

上述配置做完后,最终打包生成的dist目录多出一个images文件夹,专门用来存放组件库下的业务图片(如下图).

加载第三方组件库

如果组件库依赖了第三方组件库,比如ant design,首先需要在组件库的根目录下使用npm install antd --save安装依赖库.

antd安装完后,就可以在组件库下直接使用了.比如在源代码src/components下新建组件Empty(代码如下).

// Empty/index.tsx文件import React from 'react';
import { Empty as Ant_Empty } from 'antd';const Empty = () => {return (<Ant_Empty image={Ant_Empty.PRESENTED_IMAGE_SIMPLE} />);
};export default Empty;

Empty组件是我们基于antd做的二次封装,我们要在src/components下的入口文件index.ts导出.另外入口文件还需要引入antd的样式文件,并在文件末尾将antd内部的组件全部导出.

import 'antd/dist/antd.css';export { default as Button } from "./Button";export { default as Icon } from "./Icon";export { default as Logo } from "./Logo";export { default as Empty } from "./Empty";export * from "antd";

上述修改完后,组件库的配置文件webpack.config.js还需要添加一项,将reactantd排除,这样我们打包生成bundle.js体积变得轻量.

module.exports = {...externals: {antd: "antd",react: "react"}...

通过上述配置后,测试项目引入组件库后不再需要安装antd,测试项目可以使用组件库的自定义组件,也可以直接使用antd下的组件(代码如下).

// App.js文件(测试项目)import React from "react";
import {Button,Icon,Logo,Switch} from "ui-design-demo";
import "ui-design-demo/dist/app.css";function App() {const clickEvent = () => {console.log(123);}return (<div className="App">Hello world<Button call="按钮" onClick={clickEvent}/><Icon name="icon-zengjia" size="50"/><Logo/><Switch/></div>);
}

测试项目可直接从ui-design-demo中引用antd下定义的组件Switch使用,但要注意ui-design-demo下的自定义组件不要和antd下的组件重名(效果图如下).

按需加载

以上介绍的都是组件库的全量加载,这一小节我们探讨一下按需加载的具体实现.

如果在测试项目中使用按需加载的方式引入组件库该如何书写呢?(代码如下)

按需加载的含义就是用到哪个组件就只加载该组件的对应的jscss即可,下面代码手动引入了Button组件下的jscss.

这样一来组件库只有Button组件的代码被测试项目引用,测试项目打包后体积会因此变得小很多.

有的同学会说,为什么antd的按需加载不用写的这么麻烦,它的书写方式和全量加载一样的,根本不需要手动引入css?

这是由于babel-plugin-import这个插件发挥了功能,即使你按照全量加载的方式书写,babel-plugin-import会自动将语法编译成下面类似的形式.

import React from "react";
import Button from "ui-design-demo/es/Button";
import "ui-design-demo/es/Button/style.css";function App() {const clickEvent = () => {console.log(123);}return (<div className="App">Hello world<Button call="按钮" onClick={clickEvent}/></div>);
}export default App;

现在理解了按需加载的运行机制,那么组件库打包后应该为每一个组件都要创建一个单独的文件夹,并将它们的jscss放在一起(如下图所示).

webpack想要根据组件的个数生成多个目录,入口entry需要动态生成.output也要根据组件名称创建单独的文件夹,MiniCssExtractPlugin插件将每个组件的css代码抽离出来放入该组件对应的文件夹下.

// webpack.lazy.config.js文件const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const glob = require("glob");module.exports = (async function () {const entries = await getEntries();return {entry: entries,mode: "development",externals: {antd: "antd",react: "react"},output: {library: '[name]',libraryTarget: 'umd',filename: '[name]/index.js',path: path.resolve(__dirname, "es")}module:{... //省略},plugins: [new MiniCssExtractPlugin({filename: "[name]/style.css"})]};}())/*** 获取按需加载的入口*/
function getEntries () {return new Promise((resolve) => {const module = {};glob("./src/components/**/*.tsx", (err, files) => {files.forEach((file) => {const array = file.split("/");const name = array[array.length - 2];module[name] = file;})console.log(module);resolve(module);})})
}getEntries();

组件文档

组件库的文档可以采用docz自动生成,doczgithup地址如下:

 https://github.com/doczjs/docz

根据docz官方文档的说明,按照要求一步步做好相关的配置,最后在每一个组件目录下新建一个组件描述文件(代码如下).

// src/components/Button/Button.mdx 文件---
name: 按钮
route: /Button
menu: 业务组件
---import { Playground } from 'docz'
import Button from './index.tsx'
import './index.less'# Button 按钮button 按钮## 基本用法<Playground><Button call="按钮" />
</Playground>

输入命令启动docz就可以查看组件库的在线文档了,如下图所示.

源代码

源代码