Skip to content

Commit 16dfd3d

Browse files
committed
chore(sanity): load monorepo aliases from '@repo/dev-aliases'
1 parent 2180d0f commit 16dfd3d

File tree

9 files changed

+118
-123
lines changed

9 files changed

+118
-123
lines changed

packages/sanity/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@
270270
"@jest/globals": "^29.7.0",
271271
"@playwright/experimental-ct-react": "1.44.1",
272272
"@playwright/test": "1.44.1",
273+
"@repo/dev-aliases": "workspace:*",
273274
"@repo/package.config": "workspace:*",
274275
"@sanity/codegen": "3.58.0",
275276
"@sanity/generate-help-url": "^3.0.0",

packages/sanity/src/_internal/cli/server/__tests__/aliases.test.ts

+19-22
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import {escapeRegExp} from 'lodash'
55
import resolve from 'resolve.exports'
66
import {type Alias} from 'vite'
77

8-
import {browserCompatibleSanityPackageSpecifiers, getAliases} from '../aliases'
8+
import {
9+
browserCompatibleSanityPackageSpecifiers,
10+
getSanityPkgExportAliases,
11+
} from '../getBrowserAliases'
12+
import {getMonorepoAliases} from '../sanityMonorepo'
913

1014
const sanityPkgPath = path.resolve(__dirname, '../../../../../package.json')
1115
// eslint-disable-next-line import/no-dynamic-require
@@ -57,7 +61,7 @@ describe('getAliases', () => {
5761
// > esbuild in this environment because esbuild relies on this invariant. This
5862
// > is not a problem with esbuild. You need to fix your environment instead.
5963
it('returns the correct aliases for normal builds', () => {
60-
const aliases = getAliases({sanityPkgPath})
64+
const aliases = getSanityPkgExportAliases(sanityPkgPath)
6165

6266
// Prepare expected aliases
6367
const dirname = path.dirname(sanityPkgPath)
@@ -80,31 +84,24 @@ describe('getAliases', () => {
8084
expect(aliases).toEqual(expectedAliases)
8185
})
8286

83-
it('returns the correct aliases for the monorepo', () => {
84-
const monorepoPath = path.resolve(__dirname, '../../../../../monorepo')
87+
it('returns the correct aliases for the monorepo', async () => {
88+
const monorepoPath = '/path/to/monorepo'
8589
const devAliases = {
86-
'sanity/_singletons': 'packages/sanity/src/_singletons.ts',
87-
'sanity/desk': 'packages/sanity/src/desk.ts',
88-
'sanity/presentation': 'packages/sanity/src/presentation.ts',
90+
'sanity/_singletons': 'sanity/src/_singletons.ts',
91+
'sanity/desk': 'sanity/src/desk.ts',
92+
'sanity/presentation': 'sanity/src/presentation.ts',
8993
}
90-
jest.doMock(path.resolve(monorepoPath, 'dev/aliases.cjs'), () => devAliases, {virtual: true})
9194

92-
const aliases = getAliases({
93-
monorepo: {path: monorepoPath},
94-
})
95-
96-
const expectedAliases = Object.fromEntries(
97-
Object.entries(devAliases).map(([key, modulePath]) => {
98-
return [key, path.resolve(monorepoPath, modulePath)]
99-
}),
100-
)
95+
const expectedAliases = {
96+
'sanity/_singletons': '/path/to/monorepo/packages/sanity/src/_singletons.ts',
97+
'sanity/desk': '/path/to/monorepo/packages/sanity/src/desk.ts',
98+
'sanity/presentation': '/path/to/monorepo/packages/sanity/src/presentation.ts',
99+
}
101100

102-
expect(aliases).toMatchObject(expectedAliases)
103-
})
101+
jest.doMock('@repo/dev-aliases', () => devAliases, {virtual: true})
104102

105-
it('returns an empty object if no conditions are met', () => {
106-
const aliases = getAliases({})
103+
const aliases = await getMonorepoAliases(monorepoPath)
107104

108-
expect(aliases).toEqual({})
105+
expect(aliases).toMatchObject(expectedAliases)
109106
})
110107
})
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,18 @@
1-
import path from 'node:path'
1+
import {type AliasOptions} from 'vite'
22

3-
import {escapeRegExp} from 'lodash'
4-
import resolve from 'resolve.exports'
5-
import {type Alias, type AliasOptions} from 'vite'
6-
7-
import {type SanityMonorepo} from './sanityMonorepo'
3+
import {getSanityPkgExportAliases} from './getBrowserAliases'
4+
import {getMonorepoAliases} from './sanityMonorepo'
85

96
/**
107
* @internal
118
*/
129
export interface GetAliasesOptions {
13-
/** An optional monorepo configuration object. */
14-
monorepo?: SanityMonorepo
10+
/** An optional monorepo path. */
11+
monorepoPath?: string
1512
/** The path to the sanity package.json file. */
16-
sanityPkgPath?: string
13+
sanityPkgPath: string
1714
}
1815

19-
/**
20-
* The following are the specifiers that are expected/allowed to be used within
21-
* a built Sanity studio in the browser. These are used in combination with
22-
* `resolve.exports` to determine the final entry point locations for each allowed specifier.
23-
*
24-
* There is also a corresponding test for this file that expects these to be
25-
* included in the `sanity` package.json. That test is meant to keep this list
26-
* in sync in the event we add another package subpath.
27-
*
28-
* @internal
29-
*/
30-
export const browserCompatibleSanityPackageSpecifiers = [
31-
'sanity',
32-
'sanity/_createContext',
33-
'sanity/_singletons',
34-
'sanity/desk',
35-
'sanity/presentation',
36-
'sanity/router',
37-
'sanity/structure',
38-
'sanity/package.json',
39-
]
40-
41-
/**
42-
* These conditions should align with the conditions present in the
43-
* `package.json` of the `'sanity'` module. they are given to `resolve.exports`
44-
* in order to determine the correct entrypoint for the browser-compatible
45-
* package specifiers listed above.
46-
*/
47-
const conditions = ['import', 'browser', 'default']
48-
4916
/**
5017
* Returns an object of aliases for Vite to use.
5118
*
@@ -55,61 +22,13 @@ const conditions = ['import', 'browser', 'default']
5522
*
5623
* If the project is within the monorepo, it uses the source files directly for a better
5724
* development experience. Otherwise, it uses the `sanityPkgPath` and `conditions` to locate
58-
* the entry points for each subpath the Sanity module exports.
25+
* the entry points for each subpath of the Sanity module exports.
5926
*
6027
* @internal
6128
*/
62-
export function getAliases({monorepo, sanityPkgPath}: GetAliasesOptions): AliasOptions {
63-
// If the current Studio is located within the Sanity monorepo
64-
if (monorepo?.path) {
65-
// Load monorepo aliases. This ensures that the Vite server uses the source files
66-
// instead of the compiled output, allowing for a better development experience.
67-
const aliasesPath = path.resolve(monorepo.path, 'dev/aliases.cjs')
68-
69-
// Import the development aliases configuration
70-
// eslint-disable-next-line import/no-dynamic-require
71-
const devAliases: Record<string, string> = require(aliasesPath)
72-
73-
// Resolve each alias path relative to the monorepo path
74-
const monorepoAliases = Object.fromEntries(
75-
Object.entries(devAliases).map(([key, modulePath]) => {
76-
return [key, path.resolve(monorepo.path, modulePath)]
77-
}),
78-
)
79-
80-
// Return the aliases configuration for monorepo
81-
return monorepoAliases
82-
}
83-
84-
// If not in the monorepo, use the `sanityPkgPath`
85-
// to locate the entry points for each subpath the Sanity module exports
86-
if (sanityPkgPath) {
87-
// Load the package.json of the Sanity package
88-
// eslint-disable-next-line import/no-dynamic-require
89-
const pkg = require(sanityPkgPath)
90-
const dirname = path.dirname(sanityPkgPath)
91-
92-
// Resolve the entry points for each allowed specifier
93-
const unifiedSanityAliases = browserCompatibleSanityPackageSpecifiers.reduce<Alias[]>(
94-
(acc, next) => {
95-
// Resolve the export path for the specifier using resolve.exports
96-
const dest = resolve.exports(pkg, next, {browser: true, conditions})?.[0]
97-
if (!dest) return acc
98-
99-
// Map the specifier to its resolved path
100-
acc.push({
101-
find: new RegExp(`^${escapeRegExp(next)}$`),
102-
replacement: path.resolve(dirname, dest),
103-
})
104-
return acc
105-
},
106-
[],
107-
)
108-
109-
// Return the aliases configuration for external projects
110-
return unifiedSanityAliases
111-
}
112-
113-
// Return an empty aliases configuration if no conditions are met
114-
return {}
29+
export async function getAliases({
30+
monorepoPath,
31+
sanityPkgPath,
32+
}: GetAliasesOptions): Promise<AliasOptions> {
33+
return monorepoPath ? getMonorepoAliases(monorepoPath) : getSanityPkgExportAliases(sanityPkgPath)
11534
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import path from 'node:path'
2+
3+
import {escapeRegExp} from 'lodash'
4+
import resolve from 'resolve.exports'
5+
import {type Alias} from 'vite'
6+
7+
/**
8+
* The following are the specifiers that are expected/allowed to be used within
9+
* a built Sanity studio in the browser. These are used in combination with
10+
* `resolve.exports` to determine the final entry point locations for each allowed specifier.
11+
*
12+
* There is also a corresponding test for this file that expects these to be
13+
* included in the `sanity` package.json. That test is meant to keep this list
14+
* in sync in the event we add another package subpath.
15+
*
16+
* @internal
17+
*/
18+
export const browserCompatibleSanityPackageSpecifiers = [
19+
'sanity',
20+
'sanity/_createContext',
21+
'sanity/_singletons',
22+
'sanity/desk',
23+
'sanity/presentation',
24+
'sanity/router',
25+
'sanity/structure',
26+
'sanity/package.json',
27+
]
28+
29+
/**
30+
* These conditions should align with the conditions present in the
31+
* `package.json` of the `'sanity'` module. they are given to `resolve.exports`
32+
* in order to determine the correct entrypoint for the browser-compatible
33+
* package specifiers listed above.
34+
*/
35+
const conditions = ['import', 'browser', 'default']
36+
37+
// locate the entry points for each subpath the Sanity module exports
38+
export function getSanityPkgExportAliases(sanityPkgPath: string) {
39+
// Load the package.json of the Sanity package
40+
// eslint-disable-next-line import/no-dynamic-require
41+
const pkg = require(sanityPkgPath)
42+
const dirname = path.dirname(sanityPkgPath)
43+
44+
// Resolve the entry points for each allowed specifier
45+
const unifiedSanityAliases = browserCompatibleSanityPackageSpecifiers.reduce<Alias[]>(
46+
(acc, next) => {
47+
// Resolve the export path for the specifier using resolve.exports
48+
const dest = resolve.exports(pkg, next, {browser: true, conditions})?.[0]
49+
if (!dest) return acc
50+
51+
// Map the specifier to its resolved path
52+
acc.push({
53+
find: new RegExp(`^${escapeRegExp(next)}$`),
54+
replacement: path.resolve(dirname, dest),
55+
})
56+
return acc
57+
},
58+
[],
59+
)
60+
61+
// Return the aliases configuration for external projects
62+
return unifiedSanityAliases
63+
}

packages/sanity/src/_internal/cli/server/getViteConfig.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import debug from 'debug'
66
import readPkgUp from 'read-pkg-up'
77
import {type ConfigEnv, type InlineConfig, mergeConfig} from 'vite'
88

9-
import {getAliases} from './aliases'
109
import {createExternalFromImportMap} from './createExternalFromImportMap'
10+
import {getSanityPkgExportAliases} from './getBrowserAliases'
1111
import {getStudioEnvironmentVariables} from './getStudioEnvironmentVariables'
1212
import {normalizeBasePath} from './helpers'
13-
import {loadSanityMonorepo} from './sanityMonorepo'
13+
import {getMonorepoAliases, loadSanityMonorepo} from './sanityMonorepo'
1414
import {sanityBuildEntries} from './vite/plugin-sanity-build-entries'
1515
import {sanityDotWorkaroundPlugin} from './vite/plugin-sanity-dot-workaround'
1616
import {sanityFaviconsPlugin} from './vite/plugin-sanity-favicons'
@@ -113,7 +113,9 @@ export async function getViteConfig(options: ViteOptions): Promise<InlineConfig>
113113
envPrefix: 'SANITY_STUDIO_',
114114
logLevel: mode === 'production' ? 'silent' : 'info',
115115
resolve: {
116-
alias: getAliases({monorepo, sanityPkgPath}),
116+
alias: monorepo?.path
117+
? await getMonorepoAliases(monorepo.path)
118+
: getSanityPkgExportAliases(sanityPkgPath),
117119
dedupe: ['styled-components'],
118120
},
119121
define: {

packages/sanity/src/_internal/cli/server/renderDocument.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ import {parse as parseHtml} from 'node-html-parser'
1616
import {createElement} from 'react'
1717
import {renderToStaticMarkup} from 'react-dom/server'
1818

19-
import {getAliases} from './aliases'
2019
import {TIMESTAMPED_IMPORTMAP_INJECTOR_SCRIPT} from './constants'
2120
import {debug as serverDebug} from './debug'
22-
import {type SanityMonorepo} from './sanityMonorepo'
21+
import {getMonorepoAliases, type SanityMonorepo} from './sanityMonorepo'
2322

2423
const debug = serverDebug.extend('renderDocument')
2524

@@ -173,7 +172,9 @@ function renderDocumentFromWorkerData() {
173172
// Require hook #1
174173
// Alias monorepo modules
175174
debug('Registering potential aliases')
176-
require('module-alias').addAliases(getAliases({monorepo}))
175+
if (monorepo) {
176+
require('module-alias').addAliases(getMonorepoAliases(monorepo.path))
177+
}
177178

178179
// Require hook #2
179180
// Use `esbuild` to allow JSX/TypeScript and modern JS features

packages/sanity/src/_internal/cli/server/sanityMonorepo.ts

+9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ export interface SanityMonorepo {
99
path: string
1010
}
1111

12+
export async function getMonorepoAliases(monorepoPath: string) {
13+
const {default: aliases} = await import('@repo/dev-aliases')
14+
return Object.fromEntries(
15+
Object.entries(aliases).map(([pkgName, pkgPath]) => {
16+
return [pkgName, path.resolve(monorepoPath, path.join('packages', pkgPath))]
17+
}),
18+
)
19+
}
20+
1221
/**
1322
* Load information about the `sanity-io/sanity` monorepo (if applicable)
1423
*

packages/sanity/src/_internal/cli/threads/__tests__/validateDocuments.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {afterAll, beforeAll, describe, expect, it, jest} from '@jest/globals'
66
import {type SanityDocument, type SanityProject} from '@sanity/client'
77
import {evaluate, parse} from 'groq-js'
88

9-
import {getAliases} from '../../server/aliases'
9+
import {getMonorepoAliases} from '../../server/sanityMonorepo'
1010
import {createReceiver, type WorkerChannelReceiver} from '../../util/workerChannels'
1111
import {type ValidateDocumentsWorkerData, type ValidationWorkerChannel} from '../validateDocuments'
1212

@@ -204,7 +204,7 @@ describe('validateDocuments', () => {
204204
const moduleAlias = require('module-alias')
205205
const { register } = require('esbuild-register/dist/node')
206206
207-
moduleAlias.addAliases(${JSON.stringify(getAliases({monorepo: {path: path.resolve(__dirname, '../../../../../../..')}}))})
207+
moduleAlias.addAliases(${JSON.stringify(await getMonorepoAliases(path.resolve(__dirname, '../../../../../../..')))})
208208
209209
const { unregister } = register({
210210
target: 'node18',

pnpm-lock.yaml

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)