Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ useHead({
})

if (import.meta.server) {
setJsonLd(createWebSiteSchema())
const { siteUrl } = useAppUrls()
setJsonLd(createWebSiteSchema(siteUrl))
}

onKeyDown(
Expand Down
3 changes: 2 additions & 1 deletion app/components/AppFooter.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
const { docsUrl } = useAppUrls()
const route = useRoute()
const isHome = computed(() => route.name === 'index')

Expand Down Expand Up @@ -92,7 +93,7 @@ const showModal = () => modalRef.value?.showModal?.()
</li>
</ul>
</Modal>
<LinkBase to="https://docs.npmx.dev">
<LinkBase :to="docsUrl">
{{ $t('footer.docs') }}
</LinkBase>
<LinkBase to="https://repo.npmx.dev">
Expand Down
3 changes: 2 additions & 1 deletion app/components/AppHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ withDefaults(
},
)

const { docsUrl } = useAppUrls()
const { isConnected, npmUser } = useConnector()

const desktopLinks = computed<NavigationConfig>(() => [
Expand Down Expand Up @@ -85,7 +86,7 @@ const mobileLinks = computed<NavigationConfigWithGroups>(() => [
{
name: 'Docs',
label: $t('footer.docs'),
href: 'https://docs.npmx.dev',
href: docsUrl,
target: '_blank',
type: 'link',
external: true,
Expand Down
5 changes: 2 additions & 3 deletions app/components/Package/SkillsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ function toggleSkill(dirName: string) {
type InstallMethod = 'skills-npm' | 'skills-cli'
const selectedMethod = ref<InstallMethod>('skills-npm')

const baseUrl = computed(() =>
typeof window !== 'undefined' ? window.location.origin : 'https://npmx.dev',
)
const { siteUrl } = useAppUrls()
const baseUrl = computed(() => (typeof window !== 'undefined' ? window.location.origin : siteUrl))

const installCommand = computed(() => {
if (!props.skills.length) return null
Expand Down
11 changes: 11 additions & 0 deletions app/composables/useAppUrls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { NPMX_DOCS_SITE_PROD } from '#shared/utils/constants'

export function useAppUrls() {
const { env, siteUrl } = useAppConfig()
return {
siteUrl,
// TODO(serhalp): Handle preview environment. The docs site is a separate deployment, so we'd
// need to infer its preview URL from the site preview URL somehow...?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://vercel.com/docs/deployments/generated-urls#generated-from-git

the URL's are deterministic, so can we just construct them during the build?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as I have a feature PR stacked on this one and PRs get stale fast here 😅 and this PR leaves things no worse than before, how would you feel about following up on this later?

docsUrl: env === 'dev' ? 'http://localhost:3001' : NPMX_DOCS_SITE_PROD,
}
}
Comment on lines +3 to +11
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how useful this is - we can't get the preview url of a docs site, and we don't have a hard-coded port for the docs running locally (and this ends up being runtime code we don't really need in the site)

12 changes: 7 additions & 5 deletions app/composables/useJsonLd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ export function setJsonLd(schema: WithContext<Thing> | WithContext<Thing>[]): vo
/**
* Create WebSite schema with search action
*/
export function createWebSiteSchema(options?: {
name?: string
description?: string
}): WithContext<WebSite> {
const siteUrl = 'https://npmx.dev'
export function createWebSiteSchema(
siteUrl: string,
options?: {
name?: string
description?: string
},
): WithContext<WebSite> {
return {
'@context': 'https://schema.org',
'@type': 'WebSite',
Expand Down
3 changes: 2 additions & 1 deletion app/pages/org/[org].vue
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ function handleClearFilter(chip: FilterChip) {
const activeTab = shallowRef<'members' | 'teams'>('members')

// Canonical URL for this org page
const canonicalUrl = computed(() => `https://npmx.dev/@${orgName.value}`)
const { siteUrl } = useAppUrls()
const canonicalUrl = computed(() => `${siteUrl}/@${orgName.value}`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this ends up meaning that preview deployments get their own canonical url, and I would try to avoid that. just like with og images, you want to point to the canonical https://npmx.dev so that search engines don't end up indexing preview deployments accidentally

(I know we have a header instructing them not to, but this seems safe to hard-code. if we ever need to switch https://npmx.dev, we could easily do it throughout the codebase without much effort.)


useHead({
link: [{ rel: 'canonical', href: canonicalUrl }],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ function copyPermalinkUrl() {
}

// Canonical URL for this code page
const canonicalUrl = computed(() => `https://npmx.dev${getCodeUrl(route.params)}`)
const { siteUrl } = useAppUrls()
const canonicalUrl = computed(() => `${siteUrl}${getCodeUrl(route.params)}`)

// Toggle markdown view mode
const markdownViewModes = [
Expand Down
3 changes: 2 additions & 1 deletion app/pages/package/[[org]]/[name].vue
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,9 @@ const createPackageInfo = computed(() => {
})

// Canonical URL for this package page
const { siteUrl } = useAppUrls()
const canonicalUrl = computed(() => {
const base = `https://npmx.dev/package/${packageName.value}`
const base = `${siteUrl}/package/${packageName.value}`
return requestedVersion.value ? `${base}/v/${requestedVersion.value}` : base
})

Expand Down
8 changes: 8 additions & 0 deletions config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import Git from 'simple-git'
import * as process from 'node:process'
import { NPMX_SITE_PROD } from '../shared/utils/constants'

export { version } from '../package.json'

Expand Down Expand Up @@ -87,6 +88,11 @@ export const getProductionUrl = () =>
: undefined
: undefined

export const getSiteUrl = (isDevelopment: boolean) => {
if (isDevelopment) return 'http://localhost:3000'
Copy link
Contributor

@knowler knowler Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if we should or should not hardcode this? It is possible to pass flags with the dev command to change the port/host. Could we get that from somewhere else?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately only 127.0.0.1 works for the atproto oauth callback

but yes, you can get the actual host and port in module space

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as I have a feature PR stacked on this one and PRs get stale fast here 😅 and this PR leaves things no worse than before, how would you feel about following up on this later?

return getPreviewUrl() || getProductionUrl() || NPMX_SITE_PROD
}

const git = Git()
export async function getGitInfo() {
let branch
Expand Down Expand Up @@ -140,12 +146,14 @@ export async function getEnv(isDevelopment: boolean) {
: 'release'
const previewUrl = getPreviewUrl()
const productionUrl = getProductionUrl()
const siteUrl = getSiteUrl(isDevelopment)
return {
commit,
shortCommit,
branch,
env,
previewUrl,
productionUrl,
siteUrl,
} as const
}
11 changes: 6 additions & 5 deletions modules/build-env.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { BuildInfo, EnvType } from '../shared/types'
import { createResolver, defineNuxtModule } from 'nuxt/kit'
import { isCI } from 'std-env'
import { getEnv, getFileLastUpdated, version } from '../config/env'
import { getEnv, getFileLastUpdated, getSiteUrl, version } from '../config/env'

const { resolve } = createResolver(import.meta.url)

Expand All @@ -15,6 +15,7 @@ export default defineNuxtModule({
nuxt.options.appConfig.env = env
if (process.env.TEST) {
const time = new Date()
nuxt.options.appConfig.siteUrl = getSiteUrl(nuxt.options.dev)
nuxt.options.appConfig.buildInfo = {
env,
version: '0.0.0',
Expand All @@ -25,12 +26,11 @@ export default defineNuxtModule({
privacyPolicyDate: time.toISOString(),
} satisfies BuildInfo
} else {
const [{ env: useEnv, commit, shortCommit, branch }, privacyPolicyDate] = await Promise.all([
getEnv(nuxt.options.dev),
getFileLastUpdated('app/pages/privacy.vue'),
])
const [{ env: useEnv, commit, shortCommit, branch, siteUrl }, privacyPolicyDate] =
await Promise.all([getEnv(nuxt.options.dev), getFileLastUpdated('app/pages/privacy.vue')])
env = useEnv
nuxt.options.appConfig.env = useEnv
nuxt.options.appConfig.siteUrl = siteUrl
nuxt.options.appConfig.buildInfo = {
version,
time: +Date.now(),
Expand All @@ -52,6 +52,7 @@ export default defineNuxtModule({
declare module '@nuxt/schema' {
interface AppConfig {
env: BuildInfo['env']
siteUrl: string
buildInfo: BuildInfo
}
}
6 changes: 3 additions & 3 deletions modules/standard-site-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { defineNuxtModule, useNuxt, createResolver } from 'nuxt/kit'
import { safeParse } from 'valibot'
import * as site from '../shared/types/lexicons/site'
import { BlogPostSchema } from '../shared/schemas/blog'
import { NPMX_SITE } from '../shared/utils/constants'
import { NPMX_SITE_PROD } from '../shared/utils/constants'
import { read } from 'gray-matter'
import { TID } from '@atproto/common'
import { Client } from '@atproto/lex'
Expand Down Expand Up @@ -43,7 +43,7 @@ export default defineNuxtModule({
// Process files in parallel
await Promise.all(
batch.map(file =>
syncFile(file, NPMX_SITE, client).catch(error =>
syncFile(file, NPMX_SITE_PROD, client).catch(error =>
console.error(`[standard-site-sync] Error in ${file}:` + error),
),
),
Expand All @@ -61,7 +61,7 @@ export default defineNuxtModule({
}

// Process add/change events only
await syncFile(resolve(nuxt.options.rootDir, path), NPMX_SITE, client).catch(err =>
await syncFile(resolve(nuxt.options.rootDir, path), NPMX_SITE_PROD, client).catch(err =>
console.error(`[standard-site-sync] Failed ${path}:`, err),
)
})
Expand Down
3 changes: 2 additions & 1 deletion shared/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export const CACHE_MAX_AGE_ONE_DAY = 60 * 60 * 24
export const CACHE_MAX_AGE_ONE_YEAR = 60 * 60 * 24 * 365

// API Strings
export const NPMX_SITE = 'https://npmx.dev'
export const NPMX_SITE_PROD = 'https://npmx.dev'
export const NPMX_DOCS_SITE_PROD = 'https://docs.npmx.dev'
export const BLUESKY_API = 'https://public.api.bsky.app'
export const BLUESKY_COMMENTS_REQUEST = '/api/atproto/bluesky-comments'
export const NPM_REGISTRY = 'https://registry.npmjs.org'
Expand Down
Loading