不再写满屏import导入

密密麻麻的import语句不仅仅是一种视觉上的冲击,更是对代码组织结构的一种考验。

我们是如何做到让import“占领满屏“的了,又该如何优雅地管理这些import语句呢?

本文将从产生大量import语句的原因、可能带来的问题以及如何优化和管理import语句几个角度来进行探讨。

import是如何“占领满屏“的?

拒绝使用模块重导(Re-export

模块重导是一种通用的技术。在腾讯、字节、阿里等各大厂的组件库中都有大量使用。

如:字节的arco-design组件库中的组件:github.com/arco-design…[1]

通过重导在comonents/index.tsx文件暴露所有组件,在使用时一个import就可以使用N个组件了。

// 不使用重导
import Modal from '@arco-design/web-react/es/Modal'
import Checkbox from '@arco-design/web-react/es/Checkbox'
import Message from '@arco-design/web-react/es/Message'
...// 使用模块重导
import { Modal, Checkbox, Message} from '@arco-design/web-react'

Re-export一般用于收拢同类型的模块、一般都是以文件夹为单位,如components、routes、utils、hooks、stories等都通过各自的index.tsx暴露,这样就能极大程度的简化导入路径、提升代码可读性、可维护性

Re-export的几种形式

1. 直接重导出

直接从另一个模块重导出特定的成员。

export { foo, bar } from './moduleA';
2. 重命名并重导出(含默认导出)

从另一个模块导入成员,可能会重命名它们,然后再导出。

默认导出也可以重命名并重导出

// 通过export导出的
export { foo as newFoo, bar as newBar } from './moduleA';
// 通过export default导出的
export { default as ModuleDDefault } from './moduleD';
3. 重导出整个模块(不含默认导出)

将另一个模块的所有导出成员作为单个对象重导出。(注意:整个导出不会包含export default)

export * from './moduleA';
4. 收拢、结合导入与重导出

首先导入模块中的成员,然后使用它们,最后将其重导出。

import { foo, bar } from './moduleA';
export { foo, bar };

通过这些形式,我们可以灵活地组织和管理代码模块。每种形式都有其适用场景,选择合适的方式可以帮助我们构建出更清晰、更高效的代码结构。

从不使用require.context

require.context 是一个非常有用的功能,它允许我们动态地导入一组模块,而不需要显式地一个接一个地导入。

只需一段代码让你只管增加文件、组件,将自动收拢重导。

在项目路由、状态管理等固定场景下极其好使(能提效、尽可能避免了增加一个配置要动N个文件的情况)

尤其是在配置路由时、产生大批量的import(多少个页面就得导入多少个import)

// 不使用require.context
import A form '@/pages/A'
import B form '@/pages/B'
...// routes/index.ts文件统一处理
// 创建一个context来导入routes目录下所有的 .ts 文件
const routesContext = require.context('./routes', false, /.ts$/);
const routes = [];
// 遍历 context 中的每个模块
routesContext.keys().forEach(modulePath => {// 获取模块的导出const route = routesContext(modulePath);// 获取组件名称【如果需要话】,例如:从 "./Header.ts" 提取 "Header"// const routeName = modulePath.replace(/^./(.*).\w+$/, '$1');// 将组件存储在组件对象中routes.push(route.default || route)
});export default routes;

在大项目、多路由的情况下,使用 require.context 在处理路由导入上大有可为

从不使用import动态导入

动态import也能实现类似require.context的功能、动态收拢模块。关于import动态导入的更多内容可以看下这篇文章内的介绍《如何在Vite5➕React➕Ts项目中优雅的使用Mock数据?》[2]

对ProvidePlugin不感兴趣

webpack.ProvidePlugin是个好东西,但也不能滥用

项目中用到的变量/函数/库或工具,只要配置后就可以在任何地方使用了。

相信我--看完这个示例,如果你没用过、那你肯定会迫不及待的想要尝试了

const webpack = require('webpack');module.exports = {// 其他配置...plugins: [new webpack.ProvidePlugin({React: 'react',_: 'lodash',dayjs: 'dayjs',// 假设项目中自己定义的utils.js在src目录下Utils: path.resolve(__dirname, 'src/utils.js')
})})]// 其他配置...
};

现在你可以在任何地方使用 dayjs、lodash、Utils等,而不需要导入它

小结:

  • webpack.ProvidePlugin是一个强大的工具,它可以帮助我们减少重复的导入语句,使代码更加干净整洁。但是,它不会减少构建大小,因为这些库仍然会被包含在你的最终打包文件中。正确使用这个插件可以提高开发效率,但需要谨慎使用,以避免隐藏依赖关系,导致代码难以理解和维护。

  • 对于需要按需加载的模块或组件,考虑使用动态 import() 语法,这样可以更有效地控制代码的加载时机和减小打包体积。

  • 谨慎使用 ProvidePlugin,只为那些确实需要在多个地方使用的模块配置全局变量,以避免不必要的代码打包。

另外,如果是Vite项目可以使用vite-plugin-inject代替ProvidePlugin的功能

// 配置
import inject from 'vite-plugin-inject'; // 实测暂不可用,有替代方案再更新
...
plugins: [
inject({// 键是你想要提供的全局变量,值是你要提供的模块dayjs: 'dayjs', // 例如,这将在全局范围内提供 'dayjs',可以通过 dayjs 访问// 你可以继续添加其他需要全局提供的模块
}),
]
...

如果使用了TS,记得配置下类型:

// globals.d.ts文件 处理全局类型
import dayjs from 'dayjs';
declare global {const dayjs: typeof dayjs;
}// tsconfig.json文件 也配置一下
{ 
"compilerOptions": { 
// 编译选项... 
}, 
"include": [ "src/**/*", "globals.d.ts" // 确保 TypeScript 包括这个文件 ] 
}

大量使用Typescript导入类型

在TS项目中,满屏import肯定少不了TS的份。但如果合理配置,必定能急剧减少import的导入

这里介绍下自己在项目中使用最多的方法:TS命名空间。有了它既能让类型模块化,更过分的是在使用时可以直接不导入类型。

同样,它和ProvidePlugin一样炸裂,可以直接灭掉import导入。


使用示例:

// accout.ts
declare namespace IAccount {type IList<T = IItem> = {count: numberlist: T[]}interface IUser {id: number;name: string;avatar: string;}
}// 任意文件直接使用,无需导入
const [list, setList] = useState<IAccount.IList|undefined>();
const [user, setUser] = useState<IAccount.IUser|undefined>();

注意eslint可能需要配置下开启🔛使用命名空间

《不去充分利用bable特性》

React似乎也意识到不妥:在17版本之前,由于jsx的特性每个组件都需要明文引入import React from 'react',但在这之后由编译器自行转换,无需引入 React。如果你使用的React17之前的版本也可以通过修改babel达到这个目的,更多细节可参考React官网[3],有非常详细的说明。(也提供了自动去除引入的脚本)

其它

1. 设置webpack、ts别名。

既能缩短导入路径、也能更有语义化

resolve: {alias: {"@src": path.resolve(__dirname, 'src/'),"@components": path.resolve(__dirname, 'src/components/'),"@utils": path.resolve(__dirname, 'src/utils/')}
}// 使用别名前
import MyComponent from '../../../../components/MyComponent';// 使用别名后
import MyComponent from '@components/MyComponent';
2. 设置格式化prettier.printWidth

值设置的太小可能会导致频繁换行、给够难以阅读。其值在120较为合适吧(看团队实际的使用情况)。

{"printWidth": 120,...
}
3. 按条件动态全局加载组件

在入口文件引入全局组件,使用require.ensure或import根据条件动态加载组件,既能便于维护、减少引用、也能减少性能开销

// 异步加载全局弹窗,减少性能开销
Vue.component('IMessage', function (resolve) {// 指定条件全局加载,无需在具体页面中引用if (/^\/pagea|pageb/.test(location.pathname)) {require.ensure(['./components/message/index.vue'], function() {resolve(require('./components/message/index.vue'));});}
});
4. babel-plugin-import的使用

babel-plugin-import不是直接减少 import 的数量,而是通过优化 import 语句来减少打包体积,提高项目的加载性能。这对于使用了大型第三方库的项目来说是一个非常有价值的优化手段。

arco-design为例:

// .bablerc配置
{"plugins": [["import", {"libraryName": "@arco-design/web-react","libraryDirectory": "es", // 或者 "lib",依赖于具体使用的模块系统"style": true // 加载 CSS}, "@arco-design/web-react"]]
}
// 这个配置告诉 babel-plugin-import 自动将类似 import { Button } from '@arco-design/web-react'; 的导入语句转换为按需导入的形式,并且加载对应的 CSS 文件。
// 业务中使用
import { Button } from '@arco-design/web-react';
// 将被bable编译成
import Button from '@arco-design/web-react/es/button';
import '@arco-design/web-react/es/button/style/css.js'; // 如果 style 配置为 true

总结

导致import占满全屏的原因有很多。但不用模块重导、require.context、import动态导入、webpack.ProvidePlugin等手段,一定会让我们写出满屏的import。

只有想不到的,没有做不到的。只要你想、相信就一定能如愿以偿。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/816837.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最优算法100例之47-从尾到头打印单链表

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 从尾到头打印单链表 题解报告 方法1:头插法逆置单链表然后依次打印;注意此处是不带头结点的单链表,带头节点的操作稍微有…

Linux 网络排查命令

端口相关服务检查 netstat -ntpl|grep [$Port]说明&#xff1a;[$Port]为相应的端口号。 0.0.0.0代表本机上可用的任意地址。比如&#xff0c;0.0.0.0:80表示本机上所有地址的80端口。 tcp 0.0.0.0:80表示在所有的可用接口上监听TCP的80端口 如果返回结果为空&#xff0c;说明…

Python | Leetcode Python题解之第29题两数相除

题目&#xff1a; 题解&#xff1a; class Solution:def divide(self, dividend: int, divisor: int) -> int:INT_MIN, INT_MAX -2**31, 2**31 - 1# 考虑被除数为最小值的情况if dividend INT_MIN:if divisor 1:return INT_MINif divisor -1:return INT_MAX# 考虑除数为…

Spring ORM

Spring Data JPA 作为Spring Data 中对于关系型数据库支持的一种框架技术,属于 ORM 的一种,通过得当的使用,可以大大简化开发过程中对于数据操作的复杂度。 Java里面写的一段DB操作逻辑,是如何一步步被传递到 DB 中执行了的呢?为什么 Java 里面可以去对接不同产商的 DB 产…

仿真测试平台设计资料:921-6U CPCI卫星接口仿真测试平台

6U CPCI卫星接口仿真测试平台 一、设备概述 卫星接口仿真测试平台基于6U CPCI的结构&#xff0c;包含信号接口前板、后板&#xff0c;计算机主板、机箱、电源等硬件。硬件设计包括&#xff1a;信号接口前板、后板&#xff08;直接遥测遥控、串行RS422、LVDS&#xff0c;模拟量输…

Unity类银河恶魔城学习记录12-13 p135 Merge Skill Tree with Dogge skill源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili​​​​​​​ Inventory.cs using System.Collections.Generic; using Un…

基于springboot实现房屋租赁管理系统设计项目【项目源码+论文说明】

基于springboot实现房屋租赁管理系统设计演示 摘要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对房屋租赁信息管理混乱&…

[尚硅谷flink] 检查点笔记

在Flink中&#xff0c;有一套完整的容错机制来保证故障后的恢复&#xff0c;其中最重要的就是检查点。 文章目录 11.1 检查点11.1.1 检查点的保存1&#xff09;周期性的触发保存2&#xff09;保存的时间点3&#xff09;保存的具体流程 11.1.2 从检查点恢复状态11.1.3 检查点算法…

解读宁波TISAX:保障企业安全的关键

&#x1f352;宁波TISAX&#xff0c;❣️作为信息安全领域的&#x1f92d;重要认证体系&#xff0c;为企业&#x1f41e;提供了强大的&#x1f349;安全保障。&#x1f40b;TISAX&#xff0c;&#x1f697;全称为Trusted Information Security Assessment Exchange&#xff0c;…

【树哈希】CF1182D Complete Mirror

CF1182D - Complete Mirror Description 给定一个 n n n 个点的无根树&#xff0c;求一个树根 r o o t root root,使得对于任意两个节点 v 1 , v 2 v_1,v_2 v1​,v2​&#xff0c;若满足 d i s t ( v 1 , r o o t ) d i s t ( v 2 , r o o t ) dist(v_1,root)dist(v_2,ro…

都2024年了,线上部署你不会只会log 调试吧,Arthas了解下!

文章目录 一、什么是Arthas&#xff1f;⛅背景⚡Arthas能为我们做什么 二、部署Arthas三、Arthas 基础命令四、Arthas 项目命令实战⌚thread 线程阻塞⏰watch命令演示⚡cpu飙升演示⛽方法演示 &#x1f6a8;小结 一、什么是Arthas&#xff1f; Arthas 是一款线上监控诊断产品&a…

[Linux][基础IO][一][系统文件IO][文件描述符fd]详细解读

目录 0.预备知识1.系统文件I/O1.open2.write/read/close/lseek 2.文件描述符fd1.[0 & 1 & 2]2.什么是文件描述符&#xff1f;3.文件描述符的分配规则4.重定向5.使用dup2系统调用 -- 完成重定向6.FILE 0.预备知识 什么叫做文件呢&#xff1f; 站在系统的角度&#xff0…

解放双手,批量绕过403

将dirsearch扫描出来的结果复制到url.txt&#xff0c;如下所示 url.txt [21:18:16] 502 - 0B - /var/log/exception.log [21:18:21] 502 - 0B - /WEB-INF/jetty-env.xml [21:18:22] 502 - 0B - /WEB-INF/weblogic.xml [21:18:27] 502 - 0B - /wp-json/wp/v2/u…

Android IPC机制

在Android系统中&#xff0c;IPC&#xff08;Inter-Process Communication&#xff0c;进程间通讯&#xff09;是指在不同进程之间传送数据和通讯的机制。Android中的应用通常运行在独立的沙箱环境中的进程里&#xff0c;由于安全限制&#xff0c;这些进程无法直接访问彼此的内…

Ubuntu 22.04 开机自动挂载webdav - 设置开机自启脚本 - 解决坚果云webdav无写入权限

效果图&#xff1a; 前言&#xff1a; 1&#xff09;亲测/etc/fstab的办法没有成功自动挂载&#xff0c;换成传统的rc.local可以解决&#xff1b; 2&#xff09;rc-local.service是系统自带的一个开机自启服务&#xff0c;但是在 ubuntu 20.04 上&#xff0c;该服务默认没有开…

基于JSP的教务管理

摘要 随着现代技术的不断发展&#xff0c;计算机已经深度的应用到了当下的各个行业之中&#xff0c;教育行业也不例外。计算机对教育行业中的教务管理等内容的帮助&#xff0c;使得教职工从传统的手工办公像计算机辅助阶段迈进&#xff0c;并且实现了非常好的发展。现在的学校…

SDK-0.8.8-Release-版本+ApiMeta - ApiHug-Release

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace ​ 更…

回溯算法中常见的使用方法逻辑整理

回溯算法 常见的使用方法逻辑整理 1. 回溯算法 特点 回溯算法实际上一个类似枚举的搜索尝试过程&#xff0c;主要是在搜索尝试过程中寻找问题的解&#xff0c;当发现已不满足求解条件时&#xff0c;就“回溯”返回&#xff0c;尝试别的路径。回溯法是一种选优搜索法&#xff0…

基于springboot实现师生共评作业管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现师生共评作业管理系统演示 摘要 随着信息互联网信息的飞速发展&#xff0c;无纸化作业变成了一种趋势&#xff0c;针对这个问题开发一个专门适应师生作业交流形式的网站。本文介绍了师生共评的作业管理系统的开发全过程。通过分析企业对于师生共评的作业管理…

数据库:SQL分类之DQL详解

1.DQL语法 select 字段列表 from 表名列表 where 条件列表 group by 分组字段列表 having 分组后条件列表 order by 排序字段列表 limit 分页参数 基本查询 条件查询&#xff08;where&#xff09; 聚合函数&#xff08;count、max、min、avg、sum &#xff09; 分组查询&…