https://github.com/lisonge/vite-plugin-monkey
使用 vite-plugin-monkey 创建一个 solid-ts 的项目
vite-plugin-monkey 让开发油猴脚本和开发 web 项目一样,
拥有 模块热替换, 秒启动 等等功能,
开发体验非常不错.
安装 hope-ui 与 tanstack-query ( 原名 react-query)
"devDependencies": {
"typescript": "^4.9.3",
"vite": "^3.2.4",
"vite-plugin-monkey": "^2.9.2",
"vite-plugin-solid": "^2.4.0"
},
"dependencies": {
"@hope-ui/solid": "^0.6.7",
"@stitches/core": "^1.2.8",
"@tanstack/solid-query": "^4.15.1",
"solid-js": "^1.6.2",
"solid-transition-group": "^0.0.12"
}
修改 vite 配置
import { defineConfig } from 'vite';
import solidPlugin from 'vite-plugin-solid';
import monkey from 'vite-plugin-monkey';
export default defineConfig({
plugins: [
solidPlugin(),
monkey({
entry: 'src/index.tsx',
userscript: {
name: "github 查看 package.json 依赖",
namespace: 'npm/vite-plugin-monkey',
icon: 'https://vitejs.dev/logo.svg',
match: ['https://github.com/*'],
},
}),
],
});
程序入口 index.tsx
/* @refresh reload */
import { render } from "solid-js/web";
import App from "./components/app";
import { HopeProvider } from "@hope-ui/solid";
import { QueryClient, QueryClientProvider } from "@tanstack/solid-query";
let queryClient = new QueryClient();
render(
() => (
// 配置 hope-ui 禁止规范化 css
<HopeProvider enableCssReset={false}>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</HopeProvider>
),
(() => {
// 给 body 添加一个 div
let app = document.createElement("div");
app.id = "my-solid-root"; // 把 Solid 都放入这个 div 中
document.body.appendChild(app);
return app;
})()
);
app / index.tsx
import { Component, createSignal, For, Match, Show, Switch } from "solid-js";
import cssModule from "./index.module.css";
import {
Button,
Table,
Thead,
Tr,
Th,
Tbody,
Td,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
createDisclosure,
} from "@hope-ui/solid";
import { createQuery } from "@tanstack/solid-query";
interface IPackageJson {
dependencies: { [key: string]: string };
devDependencies: { [key: string]: string };
}
interface IPkg {
name: string;
version: string;
}
interface IQueryObj {
dep: IPkg[];
devDep: IPkg[];
}
const App: Component = () => {
const { isOpen, onOpen, onClose } = createDisclosure();
const [repoName, setRepoName] = createSignal<string>();
let query = createQuery<IQueryObj, Error>(
() => ["packageData"],
async () => {
try {
// github 文件有 5 分钟的 disk cache
let filePath = `https://raw.githubusercontent.com/${repoName()}/main/package.json`;
let apiResult: IPackageJson = await fetch(filePath).then((r) => {
if (r.status == 200) {
return r.json();
}
throw new Error("发生异常,状态码:" + r.status);
});
if (apiResult != undefined) {
console.log("来数据了");
// 运行时依赖
let depList = apiResult.dependencies;
let depArr: IPkg[] = [];
for (const key in depList) {
if (Object.prototype.hasOwnProperty.call(depList, key)) {
const value = depList[key];
depArr.push({ name: key, version: value });
}
}
// 开发依赖
let devDepArr: IPkg[] = [];
let devDepList = apiResult.devDependencies;
for (const key in devDepList) {
if (Object.prototype.hasOwnProperty.call(devDepList, key)) {
const value = devDepList[key];
devDepArr.push({ name: key, version: value });
}
}
let ret: IQueryObj = { dep: depArr, devDep: devDepArr };
return ret;
}
throw new Error("无数据");
} catch (error) {
throw error;
}
},
{
get enabled() {
let name = repoName();
return name != undefined && name != "";
},
retry: 2,
}
);
let fetchPackageJson = () => {
let sel = document.querySelector<HTMLAnchorElement>(
"#repository-container-header > div.d-flex.flex-wrap.flex-justify-end.mb-3.px-3.px-md-4.px-lg-5 > div > div > strong > a"
);
let name = sel?.href!;
if (name == undefined) {
return;
}
console.log(name);
name = name.replaceAll("https://github.com", "");
setRepoName(name);
};
let openDrawer = () => {
isOpen() ? onClose() : onOpen();
fetchPackageJson();
};
return (
<div>
<Button class={cssModule.myButton} css={{ position: "fixed" }} onClick={openDrawer}>
Open
</Button>
<Drawer opened={isOpen()} placement="top" size="lg" onClose={onClose}>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>查看项目依赖</DrawerHeader>
<DrawerBody>
<div style={{ display: "flex", "justify-content": "center" }}>
<Switch>
<Match when={query.isLoading}>
<div>loading...</div>
</Match>
<Match when={query.isError}>
<div>Error: {query!.error!.message}</div>
</Match>
<Match when={query.isSuccess}>
<Show when={query.data?.dep?.length ?? 0 > 0}>
<div>
<h1>dependencies</h1>
<Table>
<Thead>
<Tr>
<Th>名称</Th>
<Th>版本</Th>
</Tr>
</Thead>
<Tbody>
<For each={query.data?.dep}>
{(item) => {
return (
<Tr>
<Td>{item.name}</Td>
<Td>{item.version}</Td>
</Tr>
);
}}
</For>
</Tbody>
</Table>
</div>
</Show>
<Show when={query.data?.devDep?.length ?? 0 > 0}>
<div>
<h1>devDependencies</h1>
<Table>
<Thead>
<Tr>
<Th>名称</Th>
<Th>版本</Th>
</Tr>
</Thead>
<Tbody>
<For each={query.data?.devDep}>
{(item) => {
return (
<Tr>
<Td>{item.name}</Td>
<Td>{item.version}</Td>
</Tr>
);
}}
</For>
</Tbody>
</Table>
</div>
</Show>
</Match>
</Switch>
</div>
</DrawerBody>
<DrawerFooter>
<Button variant="outline" mr="$3" onClick={onClose}>
关闭
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
</div>
);
};
export default App;
app / index.module.css
.myButton {
bottom: 12px;
right: 12px;
z-index: 10;
}