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 ### 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. 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 #### 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. 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 ## Building Custom Components

View File

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

View File

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