如何在不同项目中共用前端资源,从此不加班

本文探讨了前端项目中资源复用的挑战与解决方案,介绍了如何利用npm和Webpack实现资源共用,以及Bit组件池的使用,提升开发效率,保持UI一致性。

前端时空

前端网红集结号,传递一线全栈技术,带你穿越前端时空。

前言

随着公司前端项目的增多, 大家会发现各个项目中很多资源都是是大同小异的,这就引发了一个话题,如何跨项目共用前端资源, 这里的资源泛指前端涉及到的所有静态资源, 常见的有 HTML/CSS/JS/图片等等。

所谓共用前端资源, 就是将公共的前端资源提取出来, 例如公共样式/公共逻辑/公共组件/公共图片资源等等, 让多个项目来引用, 避免复制多份, 避免重复开发, 统一管理和维护。只要更新公共资源,其他引用的项目就可以同步更新,提升开发效率,降低开发成本。

自研方案  npm 和 Webpack

想共用前端资源, 必须先将公用的前端资源以包的形式统一地管理起来, 形成一个公共仓库, 在项目中声明依赖的前端资源包, 通过工具来下载依赖的具体资源文件。

开发时使用模块打包器分析出具体的依赖文件, 打包出项目依赖的所有前端资源。

因此我们需要一个包管理器和模块打包器, 即可实现梦寐以求地共用前端资源。

  • 包管理器: npm

npm is the package manager for JavaScriptmanage dependencies in your projects

管理项目级别的依赖, 必要时搭建一套 npm 私服

  • 模块打包器: Webpack

Webpack is a module bundler for modern JavaScript applicationsit recursively builds a dependency graph that includes every module your application needs, then packages all of those modules into a small number of bundles - often only one - to be loaded by the browser.

构建工具分析并打包依赖, 现在你可以放心大胆地修改和删除项目历史遗留的静态资源文件了

  • 任何资源都可以视为一种依赖, 在构建时分析出资源的引用关系

  • 如果某个资源是僵尸资源, 删除后不会引发构建失败, 因为已经没有任何文件引用(依赖)它了

  • 在没有构建工具分析依赖的年代,你只能通过全局搜索的方式来确定一个文件还有没有用,但可能还是没有办法下达删除的决定(万一其他项目引用了呢?)

接下来, 共用前端资源的关键就是将公共的模块发布到 npm 里面, 然后就是在各个项目声明依赖实际使用了。

实际使用的方式就落在了:「如何通过 Webpack 在 HTML/CSS/JS 文件中引用 npm 模块(即 node_modules 文件夹), 或者是 npm 模块中的文件」

HTML:

<!-- 引用 npm 模块 ionicons 中的文件 -->
<img src="~ionicons/dist/svg/ios-sunny.svg" width="50" height="50">

CSS:

/* 导入 npm 模块: normalize.css, 会自动去找 main 文件 */
@import url(~normalize.css);

.test-npm-res {
    /* 引用 npm 模块 ionicons 中的文件 */
    background-image: url(~ionicons/dist/svg/ios-partly-sunny-outline.svg);
}

JS:

// 导入 npm 模块 ionicons 中的文件
import svg from 'ionicons/dist/svg/ios-sunny-outline.svg';

示例

我们只需要关注使用的模块, 不再需要关注模块的依赖了

  • 共用静态资源文件: 在各个项目中引用公共的公司 Logo 图片

将公共静态资源在 npm 上发布为一个 company-common-res 的模块包

company-common-res/
├── src/
|   |── logo.psd
|   └── ...
|
├── dist/
|   |── logo.png
|   └── ...
|
└── package.json

在项目的 package.json 中声明依赖这个模块

"dependencies": {
  "company-common-res": "^1.0.0",
}

然后就是在 HTML/CSS/JS 文件中引用这个静态资源了, 以 HTML 文件中为例

<img src="https://user-gold-cdn.xitu.io/2017/12/21/1607716e35b27686" width="50" height="50">
  • 共用 CSS 组件: 在各个项目中引用公共的 CSS 样式

将公共的 CSS 基础样式在 npm 上发布为一个 company-component-base 的模块包, 在项目的 package.json 中声明依赖这个模块  company-component-base模块的 package.json 应该声明 main 为组件的 CSS 文件"main": "company-component-base.css"

在项目中使用这个组件, 以 CSS 文件中为例

@import url(~company-component-base);

将公共的 CSS 组件在 npm 上发布为一个 company-component-button 的模块包

@import url(~company-component-button);

  • 公共 JS 模块(纯逻辑模块, 不包含样式): 在各个项目中引用公共的 JS 工具方法

将公共的 JS 工具方法在 npm 上发布为一个 company-util 的模块包, 在项目的 package.json 中声明依赖这个模块

import util from 'company-util';
util.log('test');
  • 公共 JS 组件(包含样式): 在各个项目中引用公共的 toast 组件

将 toast 组件在 npm 上发布为一个 company-component-toast 的模块包, 在项目的 package.json 中声明依赖这个模块

import Toast from 'company-component-toast';

new Toast({
    content: '提示内容'
}).show();

技术演进

随着时间的迁移,技术不断演进,我找到了一种方案————「组件池」

组件池

你想问什么是组件池?「组件池是一个复用的组件的池子,它提供的一套上传、共享的能力」。可以理解为在可视化编辑的基础上提供一个快速搬运使用代码片段的能力。任何组件都能在组件池中共存, 而且内置可视化编辑效果的 editor。组件池的重点是像 codeSandbox/codePen 然后再提供某种快速拿来使用的能力, 比如结合 vscode 的 snipshot, 或者简单点直接把代码复制张贴过来。

成本

然而实现一个上述的组件池,也就是要实现一个 codeSandbox (codeSandbox/codePen ), 成本会很高,并且内置可视化的编辑器是标配,以及便捷的共享复用能力,都需要攻克难点。于是便去寻找开源解决方案,苦苦寻觅之中,「Bit」 让我眼前一亮。

推荐方案 Bit

Github: https://github.com/teambit/bit

Bit 是一个开放源码的 cli 工具,用于跨项目和存储库的隔离组件进行协作。使用 Bit 将分散的组件从设计库或项目分发到独立的可重用包中,并在应用程序中使用它。您可以设置自己的服务器来进行组件协作,也可以使用 bit.dev 云托管进行私有和公共组件共享。

Bit 简化了 UI 组件上的协作过程。团队成员可以共享,维护和同步来自不同项目的隔离组件。

Bit 能帮助团队:

  • 提高代码可重用性

  • 提高设计和开发效率

  • 保持 UI 和 UX 的一致性

  • 增加项目的稳定性

主要特征:

  • 从现有的库或项目中提取要直接共享的组件。

  • 通过与项目的其余部分分开构建和测试每个组件,验证组件的独立性。

  • 从任何使用共享组件的应用程序中更改其源代码。

  • 在本地修改的基础上获取组件中已发布的更改。

  • 直接从使用应用程序中回馈对组件所做的更改。

  • 自动将每个组件包装为 npm 软件包。

  • 分发离散组件,而不是单个大型软件包。

  • 根据组件依赖性的变化自动进行组件版本控制。

  • 与领先的框架和工具一起使用:React,Vue,Angular,Mocha,Jest。

  • 与 Git,NPM 和 Yarn 一起使用。

Bit 可以在 Javascript 和 Javascript 框架使用

下面将教您如何使用 Bit

Bit 的使用

安装 Bit

如果您使用的是 node 8.12 及更高版本,则可以使用 NPM 或 Yarn 安装 Bit:

npm install bit-bin -g

初始化 Bit 工作区

要共享项目中的组件,应在该项目中初始化 Bit:

bit init

Bit 组件应该很小,并且只能保存组件的相关文件。但是,通常是从您正在使用的框架(例如 React 或 Vue)中导入组件,或者它们包含特定于项目的依赖项(例如Storybook)。为了确保在 Bit 组件中排除那些依赖关系,我们需要将它们配置为peerDependencies。

以下示例适用于 React,但您应将类似的方法应用于任何其他框架或其他工具和库。请查看一下您使用框架的配置规则,以获取更多信息。

为此,您需要配置您的位工作区。在package.json文件中添加与此类似的部分:

"peerDependencies": {
 "react": ">=16.9.0",
 "react-dom": ">=16.9.0",
 "styles-components": ">=4.0.0",
 "@storybook/react": ">=5.2.0"
}

跟踪 Track

要开始跟踪 Bit 中的组件,请使用add命令。组件具有其文件后,Bit可以识别并验证该组件的所有依赖项是否存在,并跟踪所有文件。Bit还可以将组件与实用程序(例如编译器或测试器)相关联,并开始隔离地构建和测试组件。

新增文件

开始跟踪项目中的组件。明确定义和隔离的组件是很好的跟踪对象。使用bit add命令跟踪组件:

bit add src/components/my-component.ts --id my-component

您可以一次跟踪多个组件:

bit add src/components/*

这将跟踪src/components目录中的所有组件。每个组件将位于以其组件ID命名的目录中。您还可以通过附加标志来将测试文件作为组件的一部分进行跟踪--tests。Bit可以隔离运行这些测试并显示结果。

使用 bit status 验证组件被跟踪,并且没有文件丢失。

添加编译器

Bit 组件可以通过以下两种方式之一在其他项目中使用:

  • 导入源代码并将其嵌入到使用项目中。

  • 安装项目将其作为 NPM 软件包使用的构建构件(例如dist目录)。

要构建组件并创建构建工件,您需要为您从项目中共享的组件定义一个编译器。编译器本身也是一个组件,因此我们使用 bit import 命令将其导入到我们的项目中:

$ bit import bit.envs/compilers/babel --compiler
the following component environments were installed
- bit.envs/compilers/babel@0.0.7
添加测试

如果您跟踪组件的测试文件,则可以定义 Bit 将用来运行它们的测试框架。像编译器一样,Bit 测试是作为组件提供的工具:

$ bit import bit.envs/testers/mocha --tester
the following component environments were installed
- bit.envs/testers/mocha@0.0.7

发布

当准备好与他人共享某个组件时,开发人员会使用遵循约定的版本号标记该组件。Bit 存储组件源代码的快照,使它可以在进行任何更改时通知使用者。开发人员可以将组件的标记版本导出到中央服务器。集中式服务器可以是自有的,也可以将bit.dev 云服务用作集中式服务器。

标签组件的版本

要为组件设置版本,请使用 bit tag 命令。Bit 锁定组件文件及其依赖关系图的状态。现在,已标记的版本是不可变的(无法更改)。在标记组件时,Bit 首先运行组件的构建和测试任务。您可以使用该 --all 标志标记工作空间中所有更改的组件。

$ bit tag --all 1.0.0
3 components tagged | 3 added, 0 changed, 0 auto-tagged
added components: components/button@1.0.0, components/login@1.0.0, components/logo@1.0.0
创建远程范围

要在不同项目之间共享组件,您需要将组件存储在远程范围内。

要设置自己的 Bit 服务器,请按照此处的说明进行操作。

或者,您可以使用 bit.dev 云托管来共享组件。通过 bit.dev 服务器共享组件。

  • 在 bit.dev 上创建一个帐户

  • 按照 bit.dev 上的步骤创建集合。在新创建的集合页面上,您可以看到导出命令,您稍后将使用该命令来导出组件。

对您自己的服务器或 bit.dev 运行位登录(如果您已经登录浏览器,位登录将自动登录到该帐户)。

$ bit login
Your browser has been opened to visit: http://bit.dev/bit-login?redirect_uri=http://localhost:8085...

您现在有了一个收藏夹。在 bit.dev 上,您可以看到导出命令,稍后将使用该命令将组件导出到该集合。

导出组件

使用bit export命令将组件从工作区发布到 bit.dev。

$ bit export user-name.collection-name
exported 3 components to collection user-name.collection-name

转到您的 bit.dev 集合。所有组件均已导出。尝试为您的组件创建并保存示例,Bit 也会在集合页面中显示为预览。

安装组件

导出后,该组件现在可供其他开发人员以以下两种方式之一使用:安装或导入。

现在,您可以使用 NPM 或 Yarn 安装组件。与其他NPM软件包一样,该组件将与构建工件(例如 dist 文件夹)一起安装。已安装的组件位于 node_modules 文件夹中。

如果使用 NPM 或 Yarn,则 NPM 应该将 Bit 配置为作用域注册表(Bit 登录时 Bit 会自动配置它):

npm config set @bit:registry https://node.bit.dev

然后,使用组件页面上的 install 命令,使用您最喜欢的软件包管理器来安装组件。范例:

npm i @bit/mui-org.material-ui.button

导入和修改

您可能需要修改组件源代码(例如,修复错误或更改功能)。为此,您需要将组件导入项目并应用更改。

现在可以对已更新的组件进行标记并重新导出,以便该组件的其他使用者可以获取更新。

导入组件

因为 Bit 隔离了组件并将它们与存储库分离,所以您可以从代码库中的任何存储库开发Bit组件。要从使用库中开发组件,请使用以下bit import命令:

bit import mui-org.material-ui/button注意:如果更改是临时的,并且您想恢复使用中的组件 node_modules,则可以使用该eject命令从本地工作区中删除组件,并将其与 NPM 客户端一起安装。

发布组件更改

对导入的组件所做的更改可以在集合中进行更新,并可以在整个项目中使用。完成更改后,可以将它们作为组件中组件的新版本进行更新(前提是您有权更新集合)。或者,可以将更改后的组件导出为新组件。使用集合中的新版本更新组件时,每个包含该组件的存储库都可以获取更改。

合并

使用 Bit,在项目中导入和修改组件时,它仍会接收对原始组件所做的修改。可以在原始项目以及导入组件的任何项目中获取更新。这有助于团队在开发来自不同项目的组件时同步更改。

bit import mui-org.material-ui/button
bit checkout mui-org.material-ui/button --interactive-merge

<think>好的,我现在需要回答用户关于如何在多个C语言文件中共享变量的问题。用户已经提供了几个引用,我需要仔细分析这些引用,并结合自己的知识来给出正确的实现方法。 首先,用户的问题是如何在多个C文件中共享同一个变量。根据引用[1],用户可能在头文件中直接定义变量,比如在Student.h中定义了int count = 0;,但这样做可能会导致重复定义的问题,因为如果多个源文件包含这个头文件,每个源文件都会有一个count的定义,链接时会出错。引用[3]中的例子也提到,不同源文件中的变量似乎有不同的值,这可能是因为变量被多次定义,导致每个文件有自己的副本。 然后看引用[2],正确的方法是在头文件中使用extern声明变量,如extern int a;,然后在某一个源文件(如status.c)中定义这个变量int a;。这样,其他文件包含头文件后,通过extern关键字来引用同一个变量,避免重复定义。这应该是正确的做法。 引用[3]中的问题可能是因为在头文件中直接定义了变量,导致每个包含该头文件的源文件都创建了自己的变量实例,而是共享同一个。正确的做法应该是使用extern在头文件中声明,再在一个源文件中定义。 接下来,引用[4]和[5]讨论了多线程中的共享变量,这可能涉及线程安全问题,但用户的问题主要是多文件共享,所以暂时需要考虑多线程的问题,除非用户提到并发访问,但当前问题中没有提到,所以可以暂涉及。 总结正确的实现步骤应该是: 1. 在头文件中使用extern声明变量。 2. 在某个源文件中定义该变量。 3. 其他文件包含该头文件,并通过extern来访问变量。 需要注意的是,能在头文件中定义变量,否则多个包含该头文件的源文件会导致多重定义错误。而使用extern声明只是告诉编译器变量在其他地方定义,会分配存储空间,因此需要在某个源文件中实际定义一次。 另外,用户提供的引用[1]中的例子是错误的,因为在头文件中直接定义了int count = 0;,这会导致每个包含该头文件的源文件都有一个count的定义,链接时会出错。正确的做法应该是在头文件中用extern声明,然后在某一个.c文件中定义。 所以,正确的步骤应该是: - 创建头文件shared.h,内容为extern int shared_var; - 在shared.c中定义int shared_var = 0; - 其他文件包含shared.h,就可以使用shared_var,且所有文件共享同一个变量。 需要提醒用户避免在头文件中定义变量,而应该使用extern声明,然后在源文件中定义一次。同时,如果需要初始化变量,应该在定义时进行,如int shared_var = 0;。 最后,生成相关问题的时候,需要考虑用户可能遇到的后续问题,比如extern的作用、头文件保护、多线程下的问题等。</think>### C语言多文件共享变量实现方法 在C语言中实现多文件共享变量需要遵循**单一定义原则**,通过`extern`关键字配合头文件使用。以下是具体实现步骤: --- #### 一、正确实现方式 1. **头文件声明外部变量** 在头文件中使用`extern`声明全局变量(分配内存): ```c // shared.h #ifndef SHARED_H #define SHARED_H extern int shared_var; // 声明变量[^2] #endif ``` 2. **源文件定义变量** 在**唯一一个源文件**中定义变量(分配实际内存): ```c // shared.c #include "shared.h" int shared_var = 0; // 实际定义并初始化[^1] ``` 3. **其他文件引用头文件** 其他文件通过包含头文件访问变量: ```c // file1.c #include "shared.h" void update_var() { shared_var = 42; // 修改共享变量 } ``` --- #### 二、常见错误分析 1. **头文件中直接定义变量** 错误示例: ```c // 错误!会导致重复定义 // bad.h int count = 0; // 每个包含此头文件的.c都会定义一次count[^3] ``` **结果**:链接阶段报错`multiple definition of 'count'`。 2. **未使用extern声明** 若仅在某个.c文件中定义变量,其他文件无法自动识别,需显式声明。 --- #### 三、高级场景处理 | 场景 | 解决方案 | |----------------|----------------------------------| | 多线程共享变量 | 使用互斥锁保护变量(如`pthread_mutex_t`)[^4][^5] | | 常量共享 | 在头文件中用`const`声明并定义(需C17及以上支持) | --- #### 四、完整代码示例 1. **项目结构** ``` project/ ├── shared.h ├── shared.c ├── file1.c └── file2.c ``` 2. **代码实现** ```c // shared.h #ifndef SHARED_H #define SHARED_H extern int shared_var; #endif // shared.c #include "shared.h" int shared_var = 100; // 初始化值 // file1.c #include "shared.h" #include <stdio.h> void print_var() { printf("File1: %d\n", shared_var); } // file2.c #include "shared.h" #include <stdio.h> void modify_var() { shared_var = 200; printf("File2: %d\n", shared_var); } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值