Fixes: FRMW-2742
In this PR, we fix the build output of the backend source code, which eliminates a lot of magic between the development and production environments.
Right now, we only compile the source files from the `src` directory and write them within the `dist` directory.
**Here's how the `src` directory with a custom module looks like**
```
src
├── modules
│ └── hello
│ ├── index.ts
```
**Here's the build output**
```
dist
├── modules
│ └── hello
│ ├── index.js
```
Let's imagine a file at the root of your project (maybe the `medusa-config.js` file) that wants to import the `modules/hello/index` file. How can we ensure that the import will work in both the development and production environments?
If we write the import targeting the `src` directory, it will break in production because it should target the `dist` directory.
## Solution
The solution is to compile everything within the project and mimic the file structure in the build output, not just the `src` directory.
**Here's how the fixed output should look like**
```
dist
├── src
│ ├── modules
│ │ └── hello
│ │ ├── index.js
├── medusa-config.js
├── yarn.lock
├── package.json
```
If you notice carefully, we also have `medusa-config.js`, `yarn.lock`, and `package.json` within the `dist` directory. We do so to create a standalone built application, something you can copy/paste to your server and run without relying on the original source code.
- This results in small containers since you are not copying unnecessary files.
- Clear distinction between the development and the production code. If you want to run the production server, then `cd` into the `dist` directory and run it from there.
## Changes in the PR
- Breaking: Remove the `dist` and `build` folders. Instead, write them production artefacts within the `.medusa` directory as `.medusa/admin` and `.medusa/server`.
- Breaking: Change the output of the `.medusa/server` folder to mimic the root project structure.
- Refactor: Remove `Symbol.for("ts-node.register.instance")]` check to find from where to load the source code.
- Refactor: Use `tsc` for creating the production build. This ensures we respect `tsconfig` settings when creating the build and also perform type-checking.
Co-authored-by: Adrien de Peretti <25098370+adrien2p@users.noreply.github.com>
80 lines
1.9 KiB
TypeScript
80 lines
1.9 KiB
TypeScript
import { logger } from "@medusajs/framework/logger"
|
|
import { AdminOptions, ConfigModule } from "@medusajs/framework/types"
|
|
import { Express } from "express"
|
|
import fs from "fs"
|
|
import path from "path"
|
|
|
|
type Options = {
|
|
app: Express
|
|
configModule: ConfigModule
|
|
rootDirectory: string
|
|
}
|
|
|
|
type IntializedOptions = Required<
|
|
Pick<AdminOptions, "path" | "disable" | "outDir">
|
|
> &
|
|
AdminOptions & {
|
|
sources?: string[]
|
|
}
|
|
|
|
const NOT_ALLOWED_PATHS = ["/auth", "/store", "/admin"]
|
|
|
|
export default async function adminLoader({
|
|
app,
|
|
configModule,
|
|
rootDirectory,
|
|
}: Options) {
|
|
const { admin } = configModule
|
|
|
|
const sources: string[] = []
|
|
|
|
const projectSource = path.join(rootDirectory, "src", "admin")
|
|
|
|
// check if the projectSource exists
|
|
if (fs.existsSync(projectSource)) {
|
|
sources.push(projectSource)
|
|
}
|
|
|
|
const adminOptions: IntializedOptions = {
|
|
disable: false,
|
|
sources,
|
|
...admin,
|
|
}
|
|
|
|
if (adminOptions?.disable) {
|
|
return app
|
|
}
|
|
|
|
if (NOT_ALLOWED_PATHS.includes(adminOptions.path)) {
|
|
logger.error(
|
|
`The 'admin.path' in 'medusa-config.js' is set to a value that is not allowed. This can prevent your server from working correctly. Please set 'admin.path' to a value that is not one of the following: ${NOT_ALLOWED_PATHS.join(
|
|
", "
|
|
)}.`
|
|
)
|
|
}
|
|
|
|
if (process.env.NODE_ENV === "development") {
|
|
return initDevelopmentServer(app, adminOptions)
|
|
}
|
|
|
|
return serveProductionBuild(app, adminOptions)
|
|
}
|
|
|
|
async function initDevelopmentServer(app: Express, options: IntializedOptions) {
|
|
const { develop } = await import("@medusajs/admin-bundler")
|
|
|
|
const adminMiddleware = await develop(options)
|
|
app.use(options.path, adminMiddleware)
|
|
return app
|
|
}
|
|
|
|
async function serveProductionBuild(app: Express, options: IntializedOptions) {
|
|
const { serve } = await import("@medusajs/admin-bundler")
|
|
|
|
const adminRoute = await serve(options)
|
|
|
|
app.use(options.path, adminRoute)
|
|
|
|
return app
|
|
}
|