const fs = require('fs') const path = require('path') const chalk = require('chalk') const { until } = require('@open-draft/until') const inquirer = require('inquirer') const invariant = require('./invariant') const { SERVICE_WORKER_BUILD_PATH } = require('../config/constants') const CWD = process.cwd() module.exports = async function init(args) { const { publicDir, save } = args // When running as a part of "postinstall" script, "cwd" equals the library's directory. // The "postinstall" script resolves the right absolute public directory path. const absolutePublicDir = path.isAbsolute(publicDir) ? publicDir : path.resolve(CWD, publicDir) const relativePublicDir = path.relative(CWD, absolutePublicDir) const dirExists = fs.existsSync(absolutePublicDir) if (!dirExists) { // Try to create the directory if it doesn't exist const [createDirectoryError] = await until(() => fs.promises.mkdir(absolutePublicDir, { recursive: true }), ) invariant( createDirectoryError == null, 'Failed to create a Service Worker at "%s": directory does not exist and could not be created.\nMake sure to include a relative path to the root directory of your server.\n\nSee the original error below:\n%s', absolutePublicDir, createDirectoryError, ) } console.log( 'Initializing the Mock Service Worker at "%s"...', absolutePublicDir, ) const serviceWorkerFilename = path.basename(SERVICE_WORKER_BUILD_PATH) const swDestFilepath = path.resolve(absolutePublicDir, serviceWorkerFilename) fs.copyFileSync(SERVICE_WORKER_BUILD_PATH, swDestFilepath) console.log(` ${chalk.green('Service Worker successfully created!')} ${chalk.gray(swDestFilepath)} Continue by creating a mocking definition module in your application: ${chalk.cyan.bold('https://mswjs.io/docs/getting-started/mocks')} `) const packageJsonPath = path.resolve(CWD, 'package.json') const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) const { msw: mswConfig } = packageJson if (mswConfig && mswConfig.workerDirectory === relativePublicDir) { return } // When called `msw init --no-save` do not show the save suggestions. if (save === false) { return } if (!mswConfig) { console.log(`\ ${chalk.cyan('INFO')} In order to ease the future updates to the worker script, we recommend saving the path to the worker directory in your package.json. `) if (save) { return saveWorkerDirectory(packageJsonPath, relativePublicDir) } return promptWorkerDirectoryUpdate( `Do you wish to save "${relativePublicDir}" as the worker directory?`, packageJsonPath, relativePublicDir, ) } if (mswConfig.workerDirectory !== relativePublicDir) { console.log( `\ ${chalk.yellowBright( 'WARN', )} The "msw.workerDirectory" in your package.json ("%s") is different from the worker directory used right now ("%s"). `, mswConfig.workerDirectory, relativePublicDir, ) if (save) { return saveWorkerDirectory(packageJsonPath, relativePublicDir) } return promptWorkerDirectoryUpdate( `Do you wish to use "${relativePublicDir}" instead of "${mswConfig.workerDirectory}" as the worker directory?`, packageJsonPath, relativePublicDir, ) } } function saveWorkerDirectory(packageJsonPath, publicDir) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) console.log( chalk.gray('Writing "msw.workerDirectory" to "%s"...'), packageJsonPath, ) const nextPackageJson = Object.assign({}, packageJson, { msw: { workerDirectory: publicDir, }, }) fs.writeFileSync( packageJsonPath, JSON.stringify(nextPackageJson, null, 2), 'utf8', ) } function promptWorkerDirectoryUpdate(message, packageJsonPath, publicDir) { return inquirer .prompt({ type: 'confirm', name: 'saveWorkerDirectory', prefix: chalk.yellowBright('?'), message, }) .then((answers) => { if (!answers.saveWorkerDirectory) { return } saveWorkerDirectory(packageJsonPath, publicDir) }) }