Skip to content

Commit

Permalink
feat: esm support (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Aug 28, 2021
1 parent a27fc1a commit eec4932
Show file tree
Hide file tree
Showing 31 changed files with 318 additions and 189 deletions.
5 changes: 2 additions & 3 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
.vscode
.github
node_modules
dist
dist-esm
dist-*
tests
jest.config.ts
jest.config.*
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": ["tsconfig.json", "tests/tsconfig.json"]
"project": ["tsconfig.json"]
},
"plugins": ["@typescript-eslint", "only-warn"],
"extends": [
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ typings/

# Nuxt.js build / generate output
.nuxt
dist
dist-*

# Gatsby files
.cache/
Expand Down
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist
dist-cjs
dist-esm
coverage
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Every-time:
With all this in place, the chain reaction goes like this:

1. You change `Nexus Prisma`
1. `Nexus Prisma` TS in watch mode emits into `dist`
1. `Nexus Prisma` TS in watch mode emits into `dist-esm` and `dist-cjs`
1. `Nexus Prisma` `nodemon` reacts to this, runs `yalc push`, Yalc emits into `Project`'s `.yalc` dir
1. `Project` `nodemon` reacts to this, runs `prisma generate`
1. You try things out with newly generated Nexus Prisma in `Project`!
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Official Prisma plugin for Nexus.
- [Prisma Schema Docs Propagation](#prisma-schema-docs-propagation)
- [As GraphQL schema doc](#as-graphql-schema-doc)
- [As JSDoc](#as-jsdoc)
- [ESM Support](#esm-support)
- [Refined DX](#refined-dx)
- [Recipes](#recipes)
- [Project relation with custom resolver logic](#project-relation-with-custom-resolver-logic)
Expand All @@ -45,6 +46,7 @@ Official Prisma plugin for Nexus.
- [For users of `nexus@=<1.0`](#for-users-of-nexus10)
- [Supported Versions Of Node](#supported-versions-of-node)
- [Supported Versions Of `@prisma/client`](#supported-versions-of-prismaclient)
- [Supported Versions Of `ts-node`](#supported-versions-of-ts-node)
- [Matrix Testing Policy](#matrix-testing-policy)
- [Patch Version Support Policy](#patch-version-support-policy)

Expand Down Expand Up @@ -796,6 +798,14 @@ User // JSDoc: A user.
User.id // JSDoc: A stable identifier to find users by.
```

### ESM Support

Nexus Prisma supports both [ESM](https://nodejs.org/api/esm.html) and CJS. There shouldn't be anything you need to "do", things should "just work". Here's the highlights of how it works though:

- We publish both a CJS and ESM build to npm.
- When the generator runs, it emits CJS code to the CJS build _and_ ESM code to the ESM build.
- Nexus Prisma CLI exists both in the ESM and CJS builds but its built to not matter which is used. That said, the package manifest is setup to run the CJS of the CLI and so that is what ends up being used in practice.

### Refined DX

These are finer points that aren't perhaps worth a top-level point but none the less add up toward a thoughtful developer experience.
Expand Down
9 changes: 9 additions & 0 deletions jest.config.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { InitialOptionsTsJest } from 'ts-jest/dist/types'

const config: InitialOptionsTsJest = {
preset: 'ts-jest',
displayName: 'e2e',
testMatch: ['**/e2e/**/*.test.ts'],
}

export default config
21 changes: 6 additions & 15 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,14 @@ import type { InitialOptionsTsJest } from 'ts-jest/dist/types'

const config: InitialOptionsTsJest = {
preset: 'ts-jest',
watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
testPathIgnorePatterns: process.env.CI ? [] : ['.*e2e.*'],
globals: {
'ts-jest': {
diagnostics: Boolean(process.env.CI)
? {
// For some reason we get these diagnostic errors in CI but only sometimes
// locally and never in editor. Furthermore the errors are invalid since they are
// explicit any not implicit any! Example error in CI https://github.com/prisma/nexus-prisma/runs/2613820675#step:9:408
ignoreCodes: [7006, 7031],
}
: false,
tsconfig: '<rootDir>/tests/tsconfig.json',
},
},
watchPlugins: [
'jest-watch-typeahead/filename',
'jest-watch-typeahead/testname',
'jest-watch-select-projects',
],
collectCoverageFrom: ['src/**/*'],
coverageReporters: ['lcov', 'text', 'html'],
projects: [`<rootDir>/jest.config.e2e.ts`, `<rootDir>/jest.config.unit.ts`],
}

export default config
9 changes: 9 additions & 0 deletions jest.config.unit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { InitialOptionsTsJest } from 'ts-jest/dist/types'

const config: InitialOptionsTsJest = {
preset: 'ts-jest',
displayName: 'unit',
testMatch: ['**/unit/**/*.test.ts', '**/lib/**/*.test.ts', '**/integration/**/*.test.ts'],
}

export default config
63 changes: 43 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,40 +1,62 @@
{
"name": "nexus-prisma",
"version": "0.0.0-dripip",
"main": "dist/index.js",
"main": "./dist-cjs/entrypoints/main.js",
"repository": "git@github.com:prisma/nexus-prisma.git",
"author": "Jason Kuhrt",
"license": "MIT",
"files": [
"dist",
"plugin.js",
"plugin.d.ts",
"scalars.js",
"scalars.d.ts",
"settings.d.ts",
"settings.js",
"generator.d.ts",
"generator.js"
"dist-cjs",
"dist-esm"
],
"exports": {
".": {
"require": "./dist-cjs/entrypoints/main.js",
"import": "./dist-esm/entrypoints/main.js"
},
"./scalars": {
"require": "./dist-cjs/entrypoints/scalars.js",
"import": "./dist-esm/entrypoints/scalars.js"
},
"./generator": {
"require": "./dist-cjs/entrypoints/generator.js",
"import": "./dist-esm/entrypoints/generator.js"
}
},
"types": "./dist-cjs/entrypoints/main.d.ts",
"typesVersions": {
"*": {
"*": [
"./dist-cjs/entrypoints/main.d.ts"
],
"scalars": [
"./dist-cjs/entrypoints/scalars.d.ts"
],
"generator": [
"./dist-cjs/entrypoints/generator.d.ts"
]
}
},
"bin": {
"nexus-prisma": "./dist/cli/nexus-prisma.js"
"nexus-prisma": "./dist-cjs/cli/nexus-prisma.js"
},
"scripts": {
"reflect:toc": "markdown-toc README.md -i --maxdepth 4 && prettier --write README.md",
"format": "prettier --write .",
"format:check": "prettier --check .",
"lint": "eslint . --ext .ts,.tsx --fix",
"lint:check": "eslint . --ext .ts,.tsx --max-warnings 0",
"dev": "tsc --build --watch",
"dev": "yarn -s clean && tsc --build --watch tsconfig.cjs.json tsconfig.esm.json",
"dev:ts": "yarn dev",
"dev:yalc": "nodemon --delay 1.5 --exec 'yalc push --no-scripts' --watch 'dist/**/*'",
"build:module-facades": "ts-node scripts/build-module-facades",
"build": "yarn clean && yarn build:module-facades && tsc",
"test": "cross-env DEBUG=e2e jest",
"test:ci": "cross-env DEBUG='e2e' jest --coverage --forceExit --runInBand",
"tdd": "jest --watch",
"tdd:e2e:debug": "cross-env test_project_reuse=true jest --watch e2e",
"clean": "rm -rf dist && rm -rf node_modules/.cache",
"dev:yalc": "nodemon --delay 1.5 --exec 'yalc push --no-scripts' --watch 'dist-*/**/*'",
"build": "yarn clean && tsc --build tsconfig.cjs.json tsconfig.esm.json",
"test": "cross-env NO_COLOR=true DEBUG=e2e jest",
"test:e2e": "cross-env NO_COLOR=true DEBUG=e2e jest --selectProjects e2e",
"test:unit": "cross-env NO_COLOR=true jest --selectProjects unit",
"test:ci": "cross-env DEBUG=e2e jest --coverage --forceExit --runInBand",
"tdd": "jest --selectProjects unit --watch",
"tdd:e2e:debug": "cross-env test_project_reuse=true jest --selectProjects e2e --watch",
"clean": "rm -rf dist-cjs dist-esm node_modules/.cache",
"release:pr": "dripip pr",
"release:canary": "dripip preview",
"release:stable": "dripip stable",
Expand Down Expand Up @@ -66,6 +88,7 @@
"graphql-request": "^3.5.0",
"graphql-tag": "^2.12.5",
"jest": "27.0.6",
"jest-watch-select-projects": "^2.0.0",
"jest-watch-typeahead": "0.6.4",
"markdown-toc": "^1.2.0",
"nexus": "^1.1.0",
Expand Down
52 changes: 0 additions & 52 deletions scripts/build-module-facades.ts

This file was deleted.

6 changes: 3 additions & 3 deletions src/index.ts → src/entrypoints/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { PackageJson } from 'type-fest'
import { inspect } from 'util'
import { enforceValidPeerDependencies } from './lib/peerDepValidator'
import { enforceValidPeerDependencies } from '../lib/peerDepValidator'

// Want synchronous cached require here
// eslint-disable-next-line
const packageJson = require('../package.json') as PackageJson
const packageJson = require('../../package.json') as PackageJson

if (!packageJson || !packageJson.version || !packageJson.name) {
console.warn(
Expand All @@ -18,4 +18,4 @@ if (!packageJson || !packageJson.version || !packageJson.name) {
})
}

export * from './runtime'
export * from '../runtime'
70 changes: 59 additions & 11 deletions src/generator/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { Gentime } from './gentime/settingsSingleton'
import * as ModelsGenerator from './models'
import { ModuleSpec } from './types'

const OUTPUT_SOURCE_DIR = getOutputSourceDir()
const OUTPUT_SOURCE_DIR_ESM = getOutputSourceDir({ esm: true })
const OUTPUT_SOURCE_DIR_CJS = getOutputSourceDir({ esm: false })

/** Generate the Nexus Prisma runtime files and emit them into a "hole" in the internal package source tree. */
export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Settings): void {
Expand All @@ -19,15 +20,43 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se
fs.write('dmmf.json', dmmf)
}

const sourceFiles: ModuleSpec[] = [
ModelsGenerator.JS.createModuleSpec(settings),
ModelsGenerator.TS.createModuleSpec(dmmf, settings),
const declarationSourceFile = ModelsGenerator.TS.createModuleSpec(dmmf, settings)

// ESM

const esmSourceFiles: ModuleSpec[] = [
ModelsGenerator.JS.createModuleSpec({
gentimeSettings: settings,
esm: true,
dmmf,
}),
declarationSourceFile,
]

fs.remove(OUTPUT_SOURCE_DIR)
fs.remove(OUTPUT_SOURCE_DIR_ESM)

esmSourceFiles.forEach((sf) => {
const filePath = Path.join(OUTPUT_SOURCE_DIR_ESM, sf.fileName)
fs.remove(filePath)
fs.write(filePath, sf.content)
d(`did write ${filePath}`)
})

// CJS

fs.remove(OUTPUT_SOURCE_DIR_CJS)

const cjsSourceFiles: ModuleSpec[] = [
ModelsGenerator.JS.createModuleSpec({
gentimeSettings: settings,
esm: false,
dmmf,
}),
declarationSourceFile,
]

sourceFiles.forEach((sf) => {
const filePath = Path.join(OUTPUT_SOURCE_DIR, sf.fileName)
cjsSourceFiles.forEach((sf) => {
const filePath = Path.join(OUTPUT_SOURCE_DIR_CJS, sf.fileName)
fs.remove(filePath)
fs.write(filePath, sf.content)
d(`did write ${filePath}`)
Expand All @@ -39,7 +68,16 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Se
/** Transform the given DMMF into JS source code with accompanying TS declarations. */
export function generateRuntime(dmmf: DMMF.Document, settings: Gentime.Settings): ModuleSpec[] {
const sourceFiles: ModuleSpec[] = [
ModelsGenerator.JS.createModuleSpec(settings),
ModelsGenerator.JS.createModuleSpec({
gentimeSettings: settings,
esm: true,
dmmf,
}),
ModelsGenerator.JS.createModuleSpec({
gentimeSettings: settings,
esm: false,
dmmf,
}),
ModelsGenerator.TS.createModuleSpec(dmmf, settings),
]

Expand All @@ -52,7 +90,7 @@ export function generateRuntime(dmmf: DMMF.Document, settings: Gentime.Settings)
* If the Yalc issue https://github.com/wclr/yalc/issues/156 is resolved then this should be as simple as
* using __dirname.
*/
function getOutputSourceDir(): string {
function getOutputSourceDir(params: { esm: boolean }): string {
let outputSourceDir: string

if (process.env.npm_package_dependencies_nexus_prisma === 'file:.yalc/nexus-prisma') {
Expand All @@ -62,9 +100,19 @@ function getOutputSourceDir(): string {
`Nexus Prisma error: Could not find the project root. Project root is the nearest ancestor directory to where this module is running (${__filename}) containing a package.json. Without this information Nexus Prisma does not know where to output its generated code.`
)
}
outputSourceDir = Path.join(Path.dirname(packageJsonFilePath), 'node_modules/nexus-prisma/dist/runtime')
outputSourceDir = Path.join(
Path.dirname(packageJsonFilePath),
params.esm ? 'node_modules/nexus-prisma/dist-esm/runtime' : 'node_modules/nexus-prisma/dist-cjs/runtime'
)
} else {
outputSourceDir = Path.join(__dirname, '../runtime')
/**
* At this point in the code we don't know if the CLI running is the CJS or ESM version.
* If it is the CJS version and we're doing an ESM build then we need to adjust the __dirname value.
*/
outputSourceDir = Path.join(
params.esm ? __dirname.replace('dist-cjs', 'dist-esm') : __dirname,
'../runtime'
)
}

d(`found outputSourceDir ${outputSourceDir}`)
Expand Down
Loading

0 comments on commit eec4932

Please sign in to comment.