Skip to content

Commit 34280db

Browse files
committed
feat: add module-replacements support first class
1 parent 7b064eb commit 34280db

7 files changed

Lines changed: 126 additions & 14 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<script setup lang="ts">
2+
import type { ModuleReplacement } from 'module-replacements'
3+
4+
const props = defineProps<{
5+
replacement: ModuleReplacement
6+
}>()
7+
8+
const { t } = useI18n()
9+
10+
const message = computed(() => {
11+
switch (props.replacement.type) {
12+
case 'native':
13+
return t('package.replacement.native', {
14+
replacement: props.replacement.replacement,
15+
nodeVersion: props.replacement.nodeVersion,
16+
})
17+
case 'simple':
18+
return t('package.replacement.simple', {
19+
replacement: props.replacement.replacement,
20+
})
21+
case 'documented':
22+
return t('package.replacement.documented')
23+
case 'none':
24+
return t('package.replacement.none')
25+
}
26+
})
27+
28+
const mdnUrl = computed(() => {
29+
if (props.replacement.type !== 'native' || !props.replacement.mdnPath) return null
30+
return `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/${props.replacement.mdnPath}`
31+
})
32+
33+
const docPath = computed(() => {
34+
if (props.replacement.type !== 'documented' || !props.replacement.docPath) return null
35+
return `https://github.com/es-tooling/module-replacements/blob/main/docs/modules/${props.replacement.docPath}.md`
36+
})
37+
</script>
38+
39+
<template>
40+
<div
41+
class="border border-amber-600/40 bg-amber-500/10 rounded-lg px-3 py-2 text-base text-amber-700 dark:text-amber-400"
42+
>
43+
<h2 class="font-medium mb-1 flex items-center gap-2">
44+
<span class="i-carbon-idea w-4 h-4" aria-hidden="true" />
45+
{{ $t('package.replacement.title') }}
46+
</h2>
47+
<p class="text-sm m-0">
48+
{{ message }}
49+
<a
50+
v-if="mdnUrl"
51+
:href="mdnUrl"
52+
target="_blank"
53+
rel="noopener noreferrer"
54+
class="inline-flex items-center gap-1 ml-1 underline underline-offset-4 decoration-amber-600/60 dark:decoration-amber-400/50 hover:decoration-fg transition-colors"
55+
>
56+
{{ $t('package.replacement.mdn') }}
57+
<span class="i-carbon-launch w-3 h-3" aria-hidden="true" />
58+
</a>
59+
<a
60+
v-if="docPath"
61+
:href="docPath"
62+
target="_blank"
63+
rel="noopener noreferrer"
64+
class="inline-flex items-center gap-1 ml-1 underline underline-offset-4 decoration-amber-600/60 dark:decoration-amber-400/50 hover:decoration-fg transition-colors"
65+
>
66+
{{ $t('package.replacement.learn_more') }}
67+
<span class="i-carbon-launch w-3 h-3" aria-hidden="true" />
68+
</a>
69+
</p>
70+
</div>
71+
</template>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { ModuleReplacement } from 'module-replacements'
2+
3+
export function useModuleReplacement(packageName: MaybeRefOrGetter<string>) {
4+
return useLazyFetch<ModuleReplacement | null>(() => `/api/replacements/${toValue(packageName)}`)
5+
}

app/pages/[...package].vue

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const {
6464
onMounted(() => fetchInstallSize())
6565
6666
const { data: packageAnalysis } = usePackageAnalysis(packageName, requestedVersion)
67+
const { data: moduleReplacement } = useModuleReplacement(packageName)
6768
6869
const { data: pkg, status, error } = await usePackage(packageName, requestedVersion)
6970
const resolvedVersion = computed(() => pkg.value?.resolvedVersion ?? null)
@@ -820,12 +821,11 @@ defineOgImageComponent('Package', {
820821
</dl>
821822
</header>
822823

823-
<!-- Security vulnerabilities warning -->
824-
<PackageVulnerabilities
825-
v-if="displayVersion"
826-
:package-name="pkg.name"
827-
:version="displayVersion.version"
828-
class="area-vulns"
824+
<!-- Bad package warning -->
825+
<PackageReplacement
826+
v-if="moduleReplacement"
827+
:replacement="moduleReplacement"
828+
class="area-replacement"
829829
/>
830830

831831
<!-- Binary-only packages: Show only execute command (no install) -->
@@ -1282,6 +1282,7 @@ defineOgImageComponent('Package', {
12821282
grid-template-columns: minmax(0, 1fr);
12831283
grid-template-areas:
12841284
'header'
1285+
'replacement'
12851286
'install'
12861287
'vulns'
12871288
'sidebar'
@@ -1293,10 +1294,11 @@ defineOgImageComponent('Package', {
12931294
.package-page {
12941295
grid-template-columns: 2fr 1fr;
12951296
grid-template-areas:
1296-
'header header'
1297-
'install install'
1298-
'vulns vulns'
1299-
'readme sidebar';
1297+
'header header'
1298+
'replacement replacement'
1299+
'install install'
1300+
'vulns vulns'
1301+
'readme sidebar';
13001302
}
13011303
}
13021304
@@ -1305,17 +1307,22 @@ defineOgImageComponent('Package', {
13051307
.package-page {
13061308
grid-template-columns: 1fr 20rem;
13071309
grid-template-areas:
1308-
'header sidebar'
1309-
'install sidebar'
1310-
'vulns sidebar'
1311-
'readme sidebar';
1310+
'header sidebar'
1311+
'replacement sidebar'
1312+
'install sidebar'
1313+
'vulns sidebar'
1314+
'readme sidebar';
13121315
}
13131316
}
13141317
13151318
.area-header {
13161319
grid-area: header;
13171320
overflow-x: hidden;
13181321
}
1322+
.area-replacement {
1323+
grid-area: replacement;
1324+
overflow-x: hidden;
1325+
}
13191326
.area-install {
13201327
grid-area: install;
13211328
overflow-x: hidden;

i18n/locales/en.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@
8989
"version": "This version has been deprecated.",
9090
"no_reason": "No reason provided"
9191
},
92+
"replacement": {
93+
"title": "Heads up! You might not need this dependency.",
94+
"native": "This can be replaced with {replacement}, available since Node {nodeVersion}.",
95+
"simple": "{replacement} instead.",
96+
"documented": "This package is pretty heavy, you should consider alternatives.",
97+
"none": "This package is never needed.",
98+
"learn_more": "Learn more",
99+
"mdn": "MDN"
100+
},
92101
"stats": {
93102
"license": "License",
94103
"weekly": "Weekly",

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"@shikijs/themes": "^3.21.0",
4343
"@vueuse/core": "^14.1.0",
4444
"@vueuse/nuxt": "14.1.0",
45+
"module-replacements": "^2.11.0",
4546
"nuxt": "^4.3.0",
4647
"nuxt-og-image": "^5.1.13",
4748
"ohash": "^2.0.11",

pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { all, type ModuleReplacement } from 'module-replacements'
2+
3+
const replacementMap = new Map<string, ModuleReplacement>(
4+
all.moduleReplacements.map(r => [r.moduleName, r]),
5+
)
6+
7+
export default defineEventHandler((event): ModuleReplacement | null => {
8+
const pkg = getRouterParam(event, 'pkg')
9+
if (!pkg) return null
10+
return replacementMap.get(pkg) ?? null
11+
})

0 commit comments

Comments
 (0)