feat: allows overriding import map location (#11532)

By default, Payload only attempts to locate the import map file in the following locations:

- `src/app/(payload)/{adminroute}/importMap.js`
- `app/(payload)/{adminroute}/importMap.js`

This is fine for most projects, but sometimes you may want to place the import map - or the Payload admin directory - somewhere else.

This PR adds a new `importMapFile` property that allows you to override this heuristic and specify your own import map path.
This commit is contained in:
Alessio Gravili
2025-03-04 18:07:29 -07:00
committed by GitHub
parent 4f822a439b
commit f01cfbcc57
3 changed files with 53 additions and 15 deletions

View File

@@ -119,10 +119,32 @@ For details on how to build Custom Components, see [Building Custom Components](
### Import Map
In order for Payload to make use of [Component Paths](#component-paths), an "Import Map" is automatically generated at `app/(payload)/admin/importMap.js`. This file contains every Custom Component in your config, keyed to their respective paths. When Payload needs to lookup a component, it uses this file to find the correct import.
In order for Payload to make use of [Component Paths](#component-paths), an "Import Map" is automatically generated at either `src/app/(payload)/admin/importMap.js` or `app/(payload)/admin/importMap.js`. This file contains every Custom Component in your config, keyed to their respective paths. When Payload needs to lookup a component, it uses this file to find the correct import.
The Import Map is automatically regenerated at startup and whenever Hot Module Replacement (HMR) runs, or you can run `payload generate:importmap` to manually regenerate it.
#### Overriding Import Map Location
Using the `config.admin.importMap.importMapFile` property, you can override the location of the import map. This is useful if you want to place the import map in a different location, or if you want to use a custom file name.
```ts
import { buildConfig } from 'payload'
import { fileURLToPath } from 'node:url'
import path from 'path'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
const config = buildConfig({
// ...
admin: {
importMap: {
baseDir: path.resolve(dirname, 'src'),
importMapFile: path.resolve(dirname, 'app', '(payload)', 'custom-import-map.js'), // highlight-line
},
},
})
```
#### Custom Imports
If needed, custom items can be appended onto the Import Map. This is mostly only relevant for plugin authors who need to add a custom import that is not referenced in a known location.
@@ -146,7 +168,7 @@ export default buildConfig({
},
},
}
}
})
```
## Building Custom Components

View File

@@ -209,16 +209,29 @@ export async function writeImportMap({
log?: boolean
rootDir: string
}) {
let importMapFolderPath = ''
if (fs.existsSync(path.resolve(rootDir, `app/(payload)${config.routes.admin}/`))) {
importMapFolderPath = path.resolve(rootDir, `app/(payload)${config.routes.admin}/`)
} else if (fs.existsSync(path.resolve(rootDir, `src/app/(payload)${config.routes.admin}/`))) {
importMapFolderPath = path.resolve(rootDir, `src/app/(payload)${config.routes.admin}/`)
let importMapFilePath: string | undefined = undefined
if (config?.admin?.importMap?.importMapFile?.length) {
if (!fs.existsSync(config.admin.importMap.importMapFile)) {
throw new Error(
`Could not find the import map file at ${config.admin.importMap.importMapFile}`,
)
}
importMapFilePath = config.admin.importMap.importMapFile
} else {
const appLocation = path.resolve(rootDir, `app/(payload)${config.routes.admin}/`)
const srcAppLocation = path.resolve(rootDir, `src/app/(payload)${config.routes.admin}/`)
if (fs.existsSync(appLocation)) {
importMapFilePath = path.resolve(appLocation, fileName)
} else if (fs.existsSync(srcAppLocation)) {
importMapFilePath = path.resolve(srcAppLocation, fileName)
} else {
throw new Error(
`Could not find the payload admin directory. Looked in ${path.resolve(rootDir, `app/(payload)${config.routes.admin}/`)} and ${path.resolve(rootDir, `src/app/(payload)${config.routes.admin}/`)}`,
`Could not find Payload import map folder. Looked in ${appLocation} and ${srcAppLocation}`,
)
}
}
const imports: string[] = []
for (const [identifier, { path, specifier }] of Object.entries(importMap)) {
@@ -237,8 +250,6 @@ ${mapKeys.join(',\n')}
}
`
const importMapFilePath = path.resolve(importMapFolderPath, fileName)
if (!force) {
// Read current import map and check in the IMPORTS if there are any new imports. If not, don't write the file.
const currentImportMap = await fs.promises.readFile(importMapFilePath, 'utf-8')

View File

@@ -855,9 +855,9 @@ export type Config = {
* @default true
*/
autoGenerate?: boolean
/** The base directory for component paths starting with /.
*
* By default, this is process.cwd()
/**
* The base directory for component paths starting with /.
* @default process.cwd()
**/
baseDir?: string
/**
@@ -873,6 +873,11 @@ export type Config = {
imports: Imports
}) => void
>
/**
* If Payload cannot find the import map file location automatically,
* you can manually provide it here.
*/
importMapFile?: string
}
livePreview?: {
collections?: string[]