Skip to content

Commit

Permalink
feat(core): add --mock-browser-env flag to sanity exec command (#2319)
Browse files Browse the repository at this point in the history
  • Loading branch information
rexxars authored and mariuslundgard committed Feb 25, 2021
1 parent d2af391 commit 3493590
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 80 deletions.
49 changes: 35 additions & 14 deletions packages/@sanity/core/src/actions/exec/execScript.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
const spawn = require('child_process').spawn
const path = require('path')
const dotenv = require('dotenv')
const fse = require('fs-extra')
const yargs = require('yargs/yargs')
const {hideBin} = require('yargs/helpers')

// Try to load .env files from the current directory
// eslint-disable-next-line no-process-env
const env = process.env.SANITY_ACTIVE_ENV || process.env.NODE_ENV || 'development'
dotenv.config({path: path.join(process.cwd(), `.env.${env}`)})
function parseCliFlags(args) {
return yargs(hideBin(args.argv || process.argv)).command(
'exec [script]',
'executes given script',
(cmd) =>
cmd
.positional('script', {type: 'string', demandOption: true})
.option('with-user-token', {type: 'boolean', default: false})
.option('mock-browser-env', {type: 'boolean', default: false})
).argv
}

module.exports = async (args) => {
// In case of specifying --with-user-token <file.js>, use the "token" as the script
const script = args.argsWithoutOptions[0] || args.extOptions['with-user-token']
const withToken = Boolean(args.extOptions['with-user-token'])
const scriptPath = path.resolve(script)
module.exports = async function execScript(args, context) {
// Reparsing CLI flags for better control of binary flags
const {withUserToken, mockBrowserEnv, script} = parseCliFlags(args)
const {workDir} = context

const scriptPath = path.resolve(script || '')
if (!script) {
throw new Error('SCRIPT must be provided. `sanity exec <script>`')
}
Expand All @@ -24,12 +32,25 @@ module.exports = async (args) => {

const babel = require.resolve('./babel')
const loader = require.resolve('./pluginLoader')
const requireContext = require.resolve('./requireContext')
const nodeArgs = ['-r', babel, '-r', loader, '-r', requireContext]
.concat(withToken ? ['-r', require.resolve('./configClient')] : [])
const requireContextPath = require.resolve('./requireContext')
const browserEnvPath = require.resolve('./registerBrowserEnv')
const configClientPath = require.resolve('./configClient')
const baseArgs = mockBrowserEnv
? ['-r', browserEnvPath]
: ['-r', babel, '-r', loader, '-r', requireContextPath]

const nodeArgs = baseArgs
.concat(withUserToken ? ['-r', configClientPath] : [])
.concat(scriptPath)
.concat(args.extraArguments || [])

const proc = spawn(process.argv[0], nodeArgs, {stdio: 'inherit'})
const proc = spawn(process.argv[0], nodeArgs, {
stdio: 'inherit',
env: {
// eslint-disable-next-line no-process-env
...process.env,
SANITY_BASE_PATH: workDir,
},
})
proc.on('close', process.exit)
}
6 changes: 6 additions & 0 deletions packages/@sanity/core/src/actions/exec/registerBrowserEnv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const mockBrowserEnvironment = require('../../util/mockBrowserEnvironment')

mockBrowserEnvironment(
// eslint-disable-next-line no-process-env
process.env.SANITY_BASE_PATH
)
68 changes: 3 additions & 65 deletions packages/@sanity/core/src/actions/graphql/getSanitySchema.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,13 @@
const pirates = require('pirates')
const jsdomGlobal = require('jsdom-global')
const pluginLoader = require('@sanity/plugin-loader')
const requireContext = require('../../util/requireContext')
const registerBabelLoader = require('./registerBabelLoader')

const getFakeGlobals = () => ({
__DEV__: false,
requestAnimationFrame: (cb) => setTimeout(cb, 0),
cancelAnimationFrame: (timer) => clearTimeout(timer),
InputEvent: global.window && global.window.InputEvent,
})

function provideFakeGlobals() {
const fakeGlobals = getFakeGlobals()
const stubbedKeys = []
Object.keys(fakeGlobals).forEach((key) => {
if (!global[key]) {
global[key] = fakeGlobals[key]
stubbedKeys.push(key)
}
})

return () => {
stubbedKeys.forEach((key) => {
delete global[key]
})
}
}
const mockBrowserEnvironment = require('../../util/mockBrowserEnvironment')

function getSanitySchema(basePath) {
const domCleanup = jsdomGlobal()
const windowCleanup = () => global.window.close()
const globalCleanup = provideFakeGlobals()
const contextCleanup = requireContext.register()
const cleanupFileLoader = pirates.addHook(
(code, filename) => `module.exports = ${JSON.stringify(filename)}`,
{
ignoreNodeModules: false,
exts: getFileExtensions(),
}
)

registerBabelLoader(basePath)
pluginLoader({basePath, stubCss: true})
const cleanup = mockBrowserEnvironment(basePath)

const schemaMod = require('part:@sanity/base/schema')
const schema = schemaMod.default || schemaMod

cleanupFileLoader()
contextCleanup()
globalCleanup()
windowCleanup()
domCleanup()

cleanup()
return schema
}

function getFileExtensions() {
return [
'.jpeg',
'.jpg',
'.png',
'.gif',
'.svg',
'.webp',
'.woff',
'.woff2',
'.ttf',
'.eot',
'.otf',
]
}

module.exports = getSanitySchema
3 changes: 2 additions & 1 deletion packages/@sanity/core/src/commands/exec/execCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import lazyRequire from '@sanity/util/lib/lazyRequire'

const helpText = `
Options
--with-user-token
--with-user-token Preload access token from CLI config into 'part:@sanity/base/client' part
--mock-browser-env Mocks a browser-like environment using jsdom
Examples
# Run the script at some/script.js in Sanity context
Expand Down
72 changes: 72 additions & 0 deletions packages/@sanity/core/src/util/mockBrowserEnvironment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const pirates = require('pirates')
const jsdomGlobal = require('jsdom-global')
const pluginLoader = require('@sanity/plugin-loader')
const requireContext = require('./requireContext')
const registerBabelLoader = require('./registerBabelLoader')

const getFakeGlobals = () => ({
__DEV__: false,
requestAnimationFrame: (cb) => setTimeout(cb, 0),
cancelAnimationFrame: (timer) => clearTimeout(timer),
InputEvent: global.window && global.window.InputEvent,
})

function provideFakeGlobals() {
const fakeGlobals = getFakeGlobals()
const stubbedKeys = []
Object.keys(fakeGlobals).forEach((key) => {
if (!global[key]) {
global[key] = fakeGlobals[key]
stubbedKeys.push(key)
}
})

return () => {
stubbedKeys.forEach((key) => {
delete global[key]
})
}
}

function mockBrowserEnvironment(basePath) {
const domCleanup = jsdomGlobal()
const windowCleanup = () => global.window.close()
const globalCleanup = provideFakeGlobals()
const contextCleanup = requireContext.register()
const cleanupFileLoader = pirates.addHook(
(code, filename) => `module.exports = ${JSON.stringify(filename)}`,
{
ignoreNodeModules: false,
exts: getFileExtensions(),
}
)

registerBabelLoader(basePath)
pluginLoader({basePath, stubCss: true})

return function cleanupBrowserEnvironment() {
cleanupFileLoader()
contextCleanup()
globalCleanup()
windowCleanup()
domCleanup()
}
}

function getFileExtensions() {
return [
'.jpeg',
'.jpg',
'.png',
'.gif',
'.svg',
'.webp',
'.woff',
'.woff2',
'.ttf',
'.eot',
'.otf',
]
}

module.exports = mockBrowserEnvironment

0 comments on commit 3493590

Please sign in to comment.