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

Commit

Permalink
Fix cache invalidation in node_modules
Browse files Browse the repository at this point in the history
  • Loading branch information
Weakky committed Apr 30, 2019
1 parent 4b89717 commit 993c8b7
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 12 deletions.
46 changes: 46 additions & 0 deletions examples/minimal/src/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as path from 'path'
import { ApolloServer, makeSchema, express, yogaEject } from 'yoga'
import * as types from './graphql'
import context from './context'

export default yogaEject({
async server() {
const schema = makeSchema({
types,
outputs: {
schema: path.join(__dirname, './schema.graphql'),
typegen: path.join(__dirname, '../.yoga/nexus.ts'),
},
nonNullDefaults: {
input: true,
output: true,
},
typegenAutoConfig: {
sources: [
{
source: path.join(__dirname, './context.ts'),
alias: 'ctx',
},
],
contextType: 'ctx.Context',
},
})
const apolloServer = new ApolloServer.ApolloServer({
schema,
context,
})
const app = express()

apolloServer.applyMiddleware({ app, path: '/' })

return app
},
async startServer(app) {
return app.listen({ port: 4000 }, () => {
console.log(`🚀 Server ready at http://localhost:4000/`)
})
},
async stopServer(http) {
http.close()
},
})
2 changes: 2 additions & 0 deletions packages/yoga/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"dependencies": {
"apollo-server-express": "^2.4.8",
"callsite": "^1.0.0",
"chalk": "^2.4.2",
"chokidar": "^2.1.1",
"create-yoga": "0.0.2",
Expand All @@ -35,6 +36,7 @@
"yargs": "^13.0.0"
},
"devDependencies": {
"@types/callsite": "^1.0.30",
"@types/chokidar": "1.7.5",
"@types/dotenv": "6.1.1",
"@types/express": "4.16.1",
Expand Down
89 changes: 89 additions & 0 deletions packages/yoga/src/decache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Modified `decache` package
const path = require('path') // if module is locally defined we path.resolve it
const callsite = require('callsite')

const find = function(moduleName: string) {
if (moduleName[0] === '.') {
const stack = callsite()
for (let i in stack) {
const filename = stack[i].getFileName()
if (filename !== module.filename) {
moduleName = path.resolve(path.dirname(filename), moduleName)
break
}
}
}
try {
return require.resolve(moduleName)
} catch (e) {
return
}
}

/**
* Removes a module from the cache. We need this to re-load our http_request !
* see: http://stackoverflow.com/a/14801711/1148249
*/
const decache = function(moduleName: string) {
const foundModuleName = find(moduleName)

if (!foundModuleName) {
return
} else {
moduleName = foundModuleName
}

// Run over the cache looking for the files
// loaded by the specified module name
searchCache(moduleName, function(mod: NodeModule) {
delete require.cache[mod.id]
})

// Remove cached paths to the module.
// Thanks to @bentael for pointing this out.
Object.keys((module.constructor as any)._pathCache).forEach(function(
cacheKey,
) {
if (cacheKey.indexOf(moduleName) > -1) {
delete (module.constructor as any)._pathCache[cacheKey]
}
})
}

/**
* Runs over the cache to search for all the cached
* files
*/
const searchCache = function(moduleName: string, callback: any) {
// Resolve the module identified by the specified name
let mod: any = require.resolve(moduleName)
let visited: Record<string, boolean> = {}

// Check if the module has been resolved and found within
// the cache no else so #ignore else http://git.io/vtgMI
if (mod && (mod = require.cache[mod]) !== undefined) {
// Recursively go over the results
;(function run(current: NodeModule) {
visited[current.id] = true
// Go over each of the module's children and
// run over it
current.children.forEach(function(child) {
// ignore .node files, decachine native modules throws a
// "module did not self-register" error on second require
if (
path.extname(child.filename) !== '.node' &&
!child.filename.includes('/node_modules/') &&
!visited[child.id]
) {
run(child)
}
})

// Call the specified callback providing the
// found module
callback(current)
})(mod)
}
}

export { decache }
2 changes: 1 addition & 1 deletion packages/yoga/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from 'fs'
import * as path from 'path'
import decache from 'decache'
import * as prettier from 'prettier'
import { decache } from './decache'

/**
* Find all files recursively in a directory based on an extension
Expand Down
26 changes: 15 additions & 11 deletions packages/yoga/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ export async function watch(env?: string): Promise<void> {
info.datamodelInfoDir,
info.prismaClientDir,
),
}).on('change', async fileName => {
}).on('raw', async (eventName, fileName) => {
try {
if (
eventName === 'change' &&
info.yogaConfig.prisma &&
(fileName === path.join(info.prismaClientDir!, 'index.ts') ||
fileName === path.join(info.datamodelInfoDir!, 'datamodel-info.ts'))
Expand All @@ -70,21 +71,24 @@ export async function watch(env?: string): Promise<void> {
return Promise.resolve(true)
}
}
logger.clearConsole()
logger.info('Compiling')

const { server, startServer, stopServer } = getYogaServer(info)
if (eventName === 'change' || eventName === 'unlink') {
logger.clearConsole()
logger.info('Compiling')

if (oldServer !== undefined) {
await stopServer(oldServer)
}
const { server, startServer, stopServer } = getYogaServer(info)

if (oldServer !== undefined) {
await stopServer(oldServer)
}

const serverInstance = await server()
const serverInstance = await server()

logger.clearConsole()
logger.done('Compiled succesfully')
logger.clearConsole()
logger.done('Compiled succesfully')

oldServer = await startServer(serverInstance)
oldServer = await startServer(serverInstance)
}
} catch (e) {
console.error(pe.render(e))
}
Expand Down

0 comments on commit 993c8b7

Please sign in to comment.