背景: 现在已经有 babel-plugin-jsxFileAttribut 这个babel 插件,此插件只能在展示的 DOM 上展示组件的位置信息,但是开发者还需要手动将文件地址 复制下来 去 vscode 粘贴进来才能找到文件,比较麻烦。现在提供点击页面元素直接唤起 ide功能,方便开发者快速定位源码位置信息。 部分插件完成工作大概在一年半前,因为离职换工作,现在开源出来。有好的坑,内推我😊
需要使用到的 npm包有3个,分别是 babel-plugin-jsxFileAttribut launch-ide-loader webpack-plugin-forceinsertscripttag
(其中 launch-ide-loader 和 webpack-plugin-forceinsertscripttag 两者选一个即可,两者在不同的场景使用拥有不同的选择 )
效果:
- 开启成功在控制台有如下图的提示
-
babel-plugin-jsxFileAttribut包的功能是: 在babel编译文件阶段找到被编译的文件,并且把 文件位置信息注入到 元素标签上, 之前写过一篇文章记录这个包的用法 。仓库地址 -
webpack-plugin-forceinsertscripttag包的功能是: 在webpack打包阶段 调用html-webpack-plugin的afterTemplateExecution钩子去插入一段script,被插入的script就是唤起 IDE 的script。 (webpack-plugin-forceinsertscripttag可在 编译阶段 插入任意一段script, 欢迎大家在业务中使用) 仓库地址。 之前写过一篇文章记录这个包的用法。 此插件基于html-webpack-plugin实现的,所以你的项目如果没有使用,(已经完成了, 新的html-webpack-plugin,接入此插件不会按照预期工作,最近我会在写一个插件弥补这部分工作webpack插件:webpack-plugin-addscriptforhtmlplugin, 此插件不依赖任何webpack插件,功能和webpack-plugin-forceinsertscripttag一致 ) -
launch-ide-loader包的功能是: 在webpack打包阶段 插入一段唤起 IDE 的script。本质上和webpack-plugin-forceinsertscripttag没有区别。但是launch-ide-loader支持文件改变 (这个文件是唤起不同的IDE名字),重新再次编译,相当于支持了热更新。仓库地址
如何配置: 场景1 -> 这里的配置 适合整个团队统一使用同一个ide的情况
- 如何使用
- 首先安装
babel-plugin-jsxFileAttribut 、webpack-plugin-forceinsertscripttag
npm i babel-plugin-jsxFileAttribut webpack-plugin-forceinsertscripttag -D
- 在
babel.config.js配置(只在dev开启这个插件即可)
// babel.config.js
const basePlugins = [...] // 原来配置的 babel plugins
// isDev 根据各自的环境变量来判断
const babelPlugins = isDev
? [
...basePlugins,
[
"babel-plugin-jsxfileattribute",
{
showCompleteFilePath: true,
isShowAwakeIdeMsg: false,
},
],
]
: basePlugins;
module.exports = {
presets: ["react-app"],
plugins: babelPlugins,
};
- 在
webpack.config.js配置(只在dev开启这个插件即可)
// webpack.config.js
module.exports = {
...,
plugins: [
...,
// isDev 根据各自的环境变量来判断
isDev && new webpackPluginForceinsertscriptTag({
isShift: false,
isInsertBody: true,
jsDeferLoad: false,
jsAsyncLoad: false,
isLaunchIdeJs: true,
// ideName: 'vscode' -> 这里默认 唤起的是 vscode ide
}),
....
].filter(Boolean),
....
}
-
面对多样化的开发环境,团队成员可能采用不同的集成开发环境(
IDE),这要求我们的构建配置具备灵活性以适应每位开发者的个性化需求。具体而言,通过在webpackPluginForceInsertScriptTag插件中设定ideName参数来指定目标IDE,确实能够精准适配各成员的编辑器偏好。然而,这一配置调整因其直接作用于核心的webpack.config.js文件,不可避免地引入了一定程度的侵入性,特别是在维护大型团队项目时,这种针对特定IDE的定制化配置不易统一管理,可能导致版本控制上的困扰——每次个性化的调整都意味着此配置文件不宜直接提交至共享代码库,这无疑增加了协作的复杂度和不便,影响了团队的整体协同效率。因此,寻找一种既能够满足个性化IDE配置需求,又能保持webpack.config.js无侵入性改动的解决方案,成为了提升开发体验的关键所在。(这段话使用GPT美化了一下, 翻译一下: 团队有人用vscode有人用webstorm,那么 这个webpackPluginForceinsertscriptTag的ideName配置项 就需要定制化改动 , 那么改动的人还不能提交webpack.config.js因为会影响别人使用)
如何配置: 场景2 -> 这里的配置 适合整个团队没有强制性要求统一使用同一个ide的情况, 拥有千人千面的ide配置。但是千人千面的 ide 配置没有热更新的功能,(即改了配置文件,需要重启进行编译)
- 如何使用配置千人千面配置开发
- 首先安装
babel-plugin-jsxFileAttribut 、webpack-plugin-forceinsertscripttag
npm i babel-plugin-jsxFileAttribut webpack-plugin-forceinsertscripttag -D
- 在
babel.config.js配置 同上面 - 在
webpack.config.js配置略有不同
// webpack.config.js
/****** 定制化配置 (默认 ide 是 vscode, 这里千人千面 可以变更为 自己使用的 ide),会被 webpack-plugin-forceinsertscripttag 合并 ******/
let ignoreConfigPath = path.resolve(__dirname, "./ignore.config.js");
const isExitIgnoreConfigFile = fs.existsSync(ignoreConfigPath);
const ignoreConfig = isExitIgnoreConfigFile ? require(ignoreConfigPath) : {};
/****** 定制化配置 (默认 ide 是 vscode, 这里千人千面 可以变更为 自己使用的 ide),会被 webpack-plugin-forceinsertscripttag 合并 *****/
module.exports = {
...,
plugins: [
...,
// isDev 根据各自的环境变量来判断
isEnvDevelopment &&
new webpackPluginForceinsertscriptTag({
isShift: false,
isInsertBody: true,
jsDeferLoad: false,
jsAsyncLoad: false,
isLaunchIdeJs: true,
...ignoreConfig, // 这里的配置 有差异
}),
....
].filter(Boolean),
....
}
- 上面的核心配置就是支持了千人千面的
IDE配置,维护一个ignore.config.js, 里面存放唤起的IDE配置,这个ignore.config.js放到.gitignore文件里面去。(ideName: 用户的ide名字, userGetUrl: 自定义跳转逻辑,函数的入参数代表 文件的绝对路径, 函数的出参数代表 被 ide 唤起的协议 + 路径 + 行列)
// ignore.config.js
module.exports = {
ideName: "vscode",
// 这里的函数是自定义跳转逻辑,函数的入参数代表 文件的绝对路径, 函数的出参数代表 被 ide 唤起的协议 + 路径 + 行列
userGetUrl(completeFilepath) {
return "vscode://file" + completeFilepath;
},
};
-
核心: 通过维护
ignore.config.js里面的ideName字段配置,达到千人千面开发配置 -
此配置有个核心问题:
ignore.config.js没办法做到 热加载,即 改了ignore.config.js没办法立即生效,需要重新启动编译一次才可以
如何配置: 场景3 -> 这里的配置 适合整个团队没有强制性要求统一使用同一个ide的情况, 拥有千人千面的ide配置。但是千人千面的 ide 配置有热更新的功能,(即改了配置文件,不需要重启进行编译)
- 如何使用 配置千人千面配置开发 且热更新配置文件
- 首先安装
babel-plugin-jsxFileAttribut 、webpack-plugin-forceinsertscripttag
npm i babel-plugin-jsxFileAttribut webpack-plugin-forceinsertscripttag -D
- 在
babel.config.js配置 同上面 - 在
webpack.config.js配置略有不同
// webpack.config.js
module.exports = {
...,
module: {
rules: [
...,
{
test: require.resolve("../xxxx.js"), // 这里 随便找个项目里面的 js 文件,相当于编译此文件出发 该 loader
use: {
loader: "launch-ide-loader",
options: {
filename: path.resolve(__dirname, "./ignore.config.js"),
},
},
},
...,
]
}
....
}
- 上面的核心配置就是支持了千人千面的
IDE配置,维护一个ignore.config.js, 里面存放唤起的IDE配置,这个ignore.config.js放到.gitignore文件里面去, 且ignore.config.js支持了热更新( 在launch-ide-loader对传入的filename进行了热更新处理) - 热更新原理看仓库代码,上面提供了仓库地址
next接入:
- 启用
babel-plugin-jsxFileAttribut插件,此插件将会在DOM上携带组件的位置信息 - 在
layout.tsx里面维护如下代码: (layout.tsx只会在ssr阶段执行, 下面的 条件 require 没问题) - 长久规划,此方案废弃,改为 基于 swc 插件方式实现
// layout.tsx
let launchIDEConfig = () => '';
const isDev = process.env.NODE_ENV === 'development';
if (isDev) {
launchIDEConfig = require('cus-utils').launchIDEConfig;
}
export default async function RootLayout(props) {
return (
<html lang={locale}>
<body className="light">
{isDev ? (
<script
dangerouslySetInnerHTML={{
__html: launchIDEConfig(),
}}
/>
) : (
''
)}
</body>
</html>
);
}
总结:
- 提供3种接入方式
- 第一种适合团队统一
ide的情况 - 第二种适合团队定制化,千人千面配置的情况。但是配置文件变更不会触发热更新
- 第三种适合合团队定制化,千人千面配置的情况。配置文件变更变会触发热更新