Skip to content
This repository has been archived by the owner on Jul 27, 2020. It is now read-only.

Commit

Permalink
Merge pull request #104 from prisma/feature/eject-command
Browse files Browse the repository at this point in the history
[RFR] Implement `eject` command
  • Loading branch information
Weakky committed Mar 15, 2019
2 parents 5c46ba6 + 77636d4 commit a3f76d7
Show file tree
Hide file tree
Showing 8 changed files with 368 additions and 218 deletions.
2 changes: 1 addition & 1 deletion examples/minimal/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"module": "commonjs",
"moduleResolution": "node",
"target": "es5",
"rootDir": "./src",
"rootDir": ".",
"outDir": "dist",
"sourceMap": true,
"lib": ["es2015", "esnext.asynciterable", "es2017", "dom"],
Expand Down
258 changes: 72 additions & 186 deletions packages/yoga/src/cli/commands/build/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { existsSync, writeFileSync } from 'fs'
import { EOL } from 'os'
import * as path from 'path'
import * as ts from 'typescript'
import { findConfigFile, importYogaConfig } from '../../../config'
import { findFileByExtension } from '../../../helpers'
import { ConfigWithInfo } from '../../../types'
import { DEFAULTS } from '../../../yogaDefaults'
import {
renderIndexFile,
renderPrismaEjectFile,
renderSimpleIndexFile,
renderResolversIndex,
} from './renderers'

const diagnosticHost: ts.FormatDiagnosticsHost = {
getNewLine: () => ts.sys.newLine,
Expand All @@ -15,40 +19,15 @@ const diagnosticHost: ts.FormatDiagnosticsHost = {

export default () => {
const info = importYogaConfig()
const tsConfigPath = findConfigFile('tsconfig.json', { required: true })
const tsConfigContent = ts.readConfigFile(tsConfigPath, ts.sys.readFile)

if (tsConfigContent.error) {
throw new Error(
ts.formatDiagnosticsWithColorAndContext(
[tsConfigContent.error],
diagnosticHost,
),
)
}

const inputConfig = ts.parseJsonConfigFileContent(
tsConfigContent.config,
ts.sys,
info.projectDir,
undefined,
tsConfigPath,
)
const config = fixConfig(inputConfig, info.projectDir)
const config = readConfigFromTsConfig(info)

compile(config.fileNames, config.options)

if (!info.yogaConfig.ejectFilePath) {
const ejectFilePath = path.join(
info.projectDir,
path.dirname(DEFAULTS.ejectFilePath!),
'index.ts',
)
const ejectFilePath = writeEjectFiles(info, (filePath, content) => {
outputFile(filePath, content, config.options, info)
})

writeEntryPoint(info, ejectFilePath, config)
} else {
useEntryPoint(info, info.yogaConfig.ejectFilePath, config)
}
useEntryPoint(info, ejectFilePath, config)
}

function compile(rootNames: string[], options: ts.CompilerOptions) {
Expand All @@ -68,177 +47,41 @@ function compile(rootNames: string[], options: ts.CompilerOptions) {
}
}

/**
* Do post-processing on config options to support `ts-node`.
*/
function fixConfig(config: ts.ParsedCommandLine, projectDir: string) {
// Target ES5 output by default (instead of ES3).
if (config.options.target === undefined) {
config.options.target = ts.ScriptTarget.ES5
}

// Target CommonJS modules by default (instead of magically switching to ES6 when the target is ES6).
if (config.options.module === undefined) {
config.options.module = ts.ModuleKind.CommonJS
}

if (config.options.outDir === undefined) {
config.options.outDir = 'dist'
}

config.options.rootDir = projectDir

return config
}

function useEntryPoint(
info: ConfigWithInfo,
ejectFilePath: string,
config: ts.ParsedCommandLine,
) {
const indexFile = `
import yoga from '${getRelativePath(
path.dirname(ejectFilePath),
ejectFilePath,
)}'
async function main() {
const serverInstance = await yoga.server()
return yoga.startServer(serverInstance)
}
main()
`
const indexFile = renderIndexFile(ejectFilePath)
const indexFilePath = path.join(path.dirname(ejectFilePath), 'index.ts')

outputFile(indexFile, indexFilePath, config.options, info)
outputFile(indexFilePath, indexFile, config.options, info)
}

function writeEntryPoint(
export function writeEjectFiles(
info: ConfigWithInfo,
ejectFilePath: string,
config: ts.ParsedCommandLine,
writeFile: (filePath: string, content: string) => void,
) {
if (info.yogaConfig.ejectFilePath) {
return info.yogaConfig.ejectFilePath
}

const ejectFilePath = path.join(info.projectDir, DEFAULTS.ejectFilePath!)
const ejectFile = info.yogaConfig.prisma
? prismaIndexFile(path.dirname(ejectFilePath), info)
: simpleIndexfile(path.dirname(ejectFilePath), info)
? renderPrismaEjectFile(ejectFilePath, info)
: renderSimpleIndexFile(ejectFilePath, info)

outputFile(ejectFile, ejectFilePath, config.options, info)
writeFile(ejectFilePath, ejectFile)

const resolverIndexPath = path.join(info.yogaConfig.resolversPath, 'index.ts')

if (!existsSync(resolverIndexPath)) {
writeResolversIndexFile(info, resolverIndexPath, config)
}
}
const resolverIndexFile = renderResolversIndex(info)

function prismaIndexFile(filePath: string, info: ConfigWithInfo) {
return `
import { ApolloServer, makePrismaSchema, express } from 'yoga'
import datamodelInfo from '${getRelativePath(
filePath,
info.datamodelInfoDir!,
)}'
import { prisma } from '${getRelativePath(filePath, info.prismaClientDir!)}'
${
info.yogaConfig.contextPath
? `import context from '${getRelativePath(
filePath,
info.yogaConfig.contextPath,
)}'`
: ''
writeFile(resolverIndexPath, resolverIndexFile)
}
import * as types from '${getRelativePath(
filePath,
info.yogaConfig.resolversPath,
)}'
const schema = makePrismaSchema({
types,
prisma: {
datamodelInfo,
client: prisma
},
outputs: false
})
const apolloServer = new ApolloServer.ApolloServer({
schema,
${info.yogaConfig.contextPath ? 'context' : ''}
})
const app = express()

apolloServer.applyMiddleware({ app, path: '/' })
app.listen({ port: 4000 }, () => {
console.log(
\`🚀 Server ready at http://localhost:4000/\`,
)
})
`
}

function simpleIndexfile(filePath: string, info: ConfigWithInfo) {
return `\
import { ApolloServer, makeSchema, express } from 'yoga'
${
info.yogaConfig.contextPath
? `import context from '${getRelativePath(
filePath,
info.yogaConfig.contextPath,
)}'`
: ''
}
import * as types from '${getRelativePath(
filePath,
info.yogaConfig.resolversPath,
)}'
const schema = makeSchema({
types,
outputs: false
})
const apolloServer = new ApolloServer.ApolloServer({
schema,
${info.yogaConfig.contextPath ? 'context' : ''}
})
const app = express()
apolloServer.applyMiddleware({ app, path: '/' })
app.listen({ port: 4000 }, () => {
console.log(
\`🚀 Server ready at http://localhost:4000/\`,
)
})
`
}

function writeResolversIndexFile(
info: ConfigWithInfo,
resolverIndexPath: string,
config: ts.ParsedCommandLine,
) {
const resolversFile = findFileByExtension(
info.yogaConfig.resolversPath,
'.ts',
)
const resolverIndexFile = `\
${resolversFile
.map(
filePath =>
`export * from '${getRelativePath(
info.yogaConfig.resolversPath,
filePath,
)}'`,
)
.join(EOL)}
`
outputFile(resolverIndexFile, resolverIndexPath, config.options, info)
return ejectFilePath
}

export function getTranspiledPath(
Expand All @@ -253,8 +96,8 @@ export function getTranspiledPath(
return path.join(outDir, pathToJsFile)
}

export function getRelativePath(dir: string, filePath: string): string {
let relativePath = path.relative(dir, filePath)
export function getRelativePath(sourceDir: string, targetPath: string): string {
let relativePath = path.relative(sourceDir, targetPath)

if (!relativePath.startsWith('.')) {
relativePath = './' + relativePath
Expand All @@ -280,8 +123,8 @@ function transpileModule(
}

function outputFile(
fileContent: string,
filePath: string,
fileContent: string,
compilerOptions: ts.CompilerOptions,
info: ConfigWithInfo,
) {
Expand All @@ -294,3 +137,46 @@ function outputFile(

writeFileSync(outFilePath, transpiled)
}

function fixConfig(config: ts.ParsedCommandLine, projectDir: string) {
// Target ES5 output by default (instead of ES3).
if (config.options.target === undefined) {
config.options.target = ts.ScriptTarget.ES5
}

// Target CommonJS modules by default (instead of magically switching to ES6 when the target is ES6).
if (config.options.module === undefined) {
config.options.module = ts.ModuleKind.CommonJS
}

if (config.options.outDir === undefined) {
config.options.outDir = 'dist'
}

config.options.rootDir = projectDir

return config
}

export function readConfigFromTsConfig(info: ConfigWithInfo) {
const tsConfigPath = findConfigFile('tsconfig.json', { required: true })
const tsConfigContent = ts.readConfigFile(tsConfigPath, ts.sys.readFile)

if (tsConfigContent.error) {
throw new Error(
ts.formatDiagnosticsWithColorAndContext(
[tsConfigContent.error],
diagnosticHost,
),
)
}

const inputConfig = ts.parseJsonConfigFileContent(
tsConfigContent.config,
ts.sys,
info.projectDir,
undefined,
tsConfigPath,
)
return fixConfig(inputConfig, info.projectDir)
}
Loading

0 comments on commit a3f76d7

Please sign in to comment.