From 042933a63279d8f27c66a86afb2263f33cca09aa Mon Sep 17 00:00:00 2001 From: dnalborczyk Date: Sat, 29 Jan 2022 00:44:23 -0500 Subject: [PATCH] refactor: use fs, fs-extra, remove sander (#4319) * refactor: use fs.readFileSync * refactor: use fs.existsSync * refactor: use fs.writeFileSync * refactor: use fs.unlinkSync * refactor: use fs.readdirSync * refactor: use fs-extra.removeSync * refactor: use fs-extra.copy/copySync * remove sander * fix test --- package-lock.json | 89 +- package.json | 2 +- scripts/load-perf-config.js | 4 +- scripts/perf-init.js | 8 +- scripts/perf.js | 6 +- scripts/update-snapshots.js | 13 +- .../samples/deprecated/emit-asset/_config.js | 4 +- .../emit-file/reference-files/_config.js | 4 +- test/cli/index.js | 23 +- test/cli/samples/config-no-output/_config.js | 6 +- test/cli/samples/sourcemap-hidden/_config.js | 10 +- .../wait-for-bundle-input-object/_config.js | 6 +- .../samples/wait-for-bundle-input/_config.js | 4 +- .../samples/warn-broken-sourcemap/_config.js | 6 +- .../samples/warn-broken-sourcemaps/_config.js | 6 +- .../cli/samples/watch/bundle-error/_config.js | 6 +- test/cli/samples/watch/close-stdin/wrapper.js | 8 +- .../watch-config-early-update/_config.js | 6 +- .../watch/watch-config-error/_config.js | 6 +- .../watch-config-initial-error/_config.js | 6 +- .../watch/watch-config-no-update/_config.js | 6 +- test/form/index.js | 12 +- .../samples/deprecated/emit-asset/_config.js | 6 +- test/form/samples/emit-asset-file/_config.js | 6 +- .../emit-file-tree-shaken-access/_config.js | 4 +- .../samples/custom-loaders/_config.js | 6 +- .../custom-path-resolver-on-entry/_config.js | 4 +- .../_config.js | 4 +- .../samples/transform-without-code/_config.js | 4 +- test/hooks/index.js | 9 +- .../combined-sourcemap-with-loader/_config.js | 4 +- .../excludes-plugin-helpers/_config.js | 4 +- test/sourcemaps/samples/loaders/_config.js | 4 +- .../samples/reified-namespace/_config.js | 4 +- .../samples/single-length-segments/_config.js | 8 +- test/utils.js | 54 +- test/watch/index.js | 2245 ++++++++--------- 37 files changed, 1264 insertions(+), 1343 deletions(-) diff --git a/package-lock.json b/package-lock.json index c5f6bf4c0d5..b86953d1fb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1927,6 +1927,34 @@ "fs-extra": "^8.1.0", "matcher-collection": "^2.0.1", "walk-sync": "^2.0.2" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } } }, "flat": { @@ -1968,14 +1996,14 @@ "dev": true }, "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", "dev": true, "requires": { "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" } }, "fs.realpath": { @@ -2676,12 +2704,13 @@ } }, "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" } }, "levn": { @@ -3098,7 +3127,7 @@ "log-symbols": "4.1.0", "minimatch": "3.0.4", "ms": "2.1.3", - "nanoid": "^3.1.31", + "nanoid": "3.1.25", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -3249,7 +3278,8 @@ "nanoid": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==" + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "dev": true }, "natural-compare": { "version": "1.4.0", @@ -4082,37 +4112,6 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, - "sander": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/sander/-/sander-0.6.0.tgz", - "integrity": "sha1-rxYkzX+2362Y6+9WUxn5IAeNqSU=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.3", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.2" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -4623,9 +4622,9 @@ "dev": true }, "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, "uri-js": { diff --git a/package.json b/package.json index 98e48b00511..1ea2df6e1ea 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "eslint-plugin-prettier": "^4.0.0", "execa": "^5.1.1", "fixturify": "^2.1.1", + "fs-extra": "^10.0.0", "hash.js": "^1.1.7", "husky": "^7.0.4", "is-reference": "^3.0.0", @@ -105,7 +106,6 @@ "rollup-plugin-string": "^3.0.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-thatworks": "^1.0.4", - "sander": "^0.6.0", "shx": "^0.3.4", "signal-exit": "^3.0.6", "source-map": "^0.7.3", diff --git a/scripts/load-perf-config.js b/scripts/load-perf-config.js index 24cb396e93b..647ee9b720f 100644 --- a/scripts/load-perf-config.js +++ b/scripts/load-perf-config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { accessSync, constants } = require('fs'); const path = require('path'); const rollup = require('../dist/rollup.js'); @@ -6,7 +6,7 @@ exports.targetDir = path.resolve(__dirname, '..', 'perf'); const configFile = path.resolve(exports.targetDir, 'rollup.config.js'); try { - fs.accessSync(configFile, fs.constants.R_OK); + accessSync(configFile, constants.R_OK); } catch (e) { console.error( `No valid "rollup.config.js" in ${exports.targetDir}. Did you "npm run perf:init"?` diff --git a/scripts/perf-init.js b/scripts/perf-init.js index 6cd860f73c1..72e617d7db6 100644 --- a/scripts/perf-init.js +++ b/scripts/perf-init.js @@ -1,9 +1,9 @@ /* eslint-disable no-console */ -const fs = require('fs'); +const { accessSync, constants } = require('fs'); const path = require('path'); const execa = require('execa'); -const sander = require('sander'); +const { removeSync } = require('fs-extra'); const repoWithBranch = process.argv[2]; const TARGET_DIR = path.resolve(__dirname, '..', 'perf'); @@ -17,7 +17,7 @@ if (process.argv.length !== 3 || !VALID_REPO.test(repoWithBranch)) { process.exit(1); } console.error(`Cleaning up '${TARGET_DIR}'...`); -sander.rimrafSync(TARGET_DIR); +removeSync(TARGET_DIR); const [, repo, , branch] = VALID_REPO.exec(repoWithBranch); @@ -43,7 +43,7 @@ async function setupNewRepo(repo, branch) { gitArgs.push(`https://github.com/${repo}.git`, TARGET_DIR); await execWithOutput('git', gitArgs); try { - fs.accessSync(path.resolve(TARGET_DIR, 'rollup.config.js'), fs.constants.R_OK); + accessSync(path.resolve(TARGET_DIR, 'rollup.config.js'), constants.R_OK); } catch (e) { throw new Error('The repository needs to have a file "rollup.config.js" at the top level.'); } diff --git a/scripts/perf.js b/scripts/perf.js index 0ccbeaacd25..be74ae5c56f 100644 --- a/scripts/perf.js +++ b/scripts/perf.js @@ -1,6 +1,6 @@ /* global gc */ -const fs = require('fs'); +const { readFileSync, writeFileSync } = require('fs'); const path = require('path'); const colorette = require('colorette'); const prettyBytes = require('pretty-bytes'); @@ -137,7 +137,7 @@ function clearLines(numberOfLines) { function getExistingTimings() { try { - const timings = JSON.parse(fs.readFileSync(perfFile, 'utf8')); + const timings = JSON.parse(readFileSync(perfFile, 'utf8')); console.info( colorette.bold( `Comparing with ${colorette.cyan(perfFile)}. Delete this file to create a new base line.` @@ -151,7 +151,7 @@ function getExistingTimings() { function persistTimings(timings) { try { - fs.writeFileSync(perfFile, JSON.stringify(timings, null, 2), 'utf8'); + writeFileSync(perfFile, JSON.stringify(timings, null, 2), 'utf8'); console.info( colorette.bold( `Saving performance information to new reference file ${colorette.cyan(perfFile)}.` diff --git a/scripts/update-snapshots.js b/scripts/update-snapshots.js index b7e9ee3223a..79b6e28fde8 100755 --- a/scripts/update-snapshots.js +++ b/scripts/update-snapshots.js @@ -1,7 +1,8 @@ #!/usr/bin/env node +const { readdirSync } = require('fs'); const { resolve, join } = require('path'); -const { readdirSync, copydirSync, copyFileSync, rimrafSync } = require('sander'); +const { copySync, removeSync } = require('fs-extra'); const basePath = resolve(__dirname, '../test'); @@ -14,10 +15,10 @@ for (const dir of formDirsToHandle) { formDirsToHandle.push(...testFiles.map(filename => join(dir, filename))); } else if (testFiles.includes('_actual')) { const expectedPath = join(testPath, '_expected'); - rimrafSync(expectedPath); - copydirSync(join(testPath, '_actual')).to(expectedPath); + removeSync(expectedPath); + copySync(join(testPath, '_actual'), expectedPath); } else if (testFiles.includes('_actual.js')) { - copyFileSync(join(testPath, '_actual.js')).to(join(testPath, '_expected.js')); + copySync(join(testPath, '_actual.js'), join(testPath, '_expected.js')); } else { throw new Error(`Could not find test output in ${testPath}`); } @@ -32,8 +33,8 @@ for (const dir of chunkingDirsToHandle) { chunkingDirsToHandle.push(...testFiles.map(filename => join(dir, filename))); } else if (testFiles.includes('_actual')) { const expectedPath = join(testPath, '_expected'); - rimrafSync(expectedPath); - copydirSync(join(testPath, '_actual')).to(expectedPath); + removeSync(expectedPath); + copySync(join(testPath, '_actual'), expectedPath); } else { throw new Error(`Could not find test output in ${testPath}`); } diff --git a/test/chunking-form/samples/deprecated/emit-asset/_config.js b/test/chunking-form/samples/deprecated/emit-asset/_config.js index dad3aeeaf09..f9625ac7974 100644 --- a/test/chunking-form/samples/deprecated/emit-asset/_config.js +++ b/test/chunking-form/samples/deprecated/emit-asset/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); module.exports = { @@ -21,7 +21,7 @@ module.exports = { if (id.endsWith('.svg')) { return `export default import.meta.ROLLUP_ASSET_URL_${this.emitAsset( path.basename(id), - fs.readFileSync(id) + readFileSync(id) )};`; } } diff --git a/test/chunking-form/samples/emit-file/reference-files/_config.js b/test/chunking-form/samples/emit-file/reference-files/_config.js index 57ba1d3de55..6569204399f 100644 --- a/test/chunking-form/samples/emit-file/reference-files/_config.js +++ b/test/chunking-form/samples/emit-file/reference-files/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); module.exports = { @@ -21,7 +21,7 @@ module.exports = { return `export default import.meta.ROLLUP_FILE_URL_${this.emitFile({ type: 'asset', name: path.basename(id), - source: fs.readFileSync(id) + source: readFileSync(id) })};`; } } diff --git a/test/cli/index.js b/test/cli/index.js index 267b0b27e2d..15c32331e0e 100644 --- a/test/cli/index.js +++ b/test/cli/index.js @@ -1,7 +1,9 @@ const assert = require('assert'); const { exec } = require('child_process'); -const path = require('path'); -const sander = require('sander'); +const { existsSync, readFileSync } = require('fs'); +const { basename, resolve, sep } = require('path'); +const process = require('process'); +const { copySync, removeSync, statSync } = require('fs-extra'); const { normaliseOutput, runTestSuiteWithSamples, @@ -11,12 +13,12 @@ const { const cwd = process.cwd(); -sander.rimrafSync(__dirname, 'node_modules'); -sander.copydirSync(__dirname, 'node_modules_rename_me').to(__dirname, 'node_modules'); +removeSync(resolve(__dirname, 'node_modules')); +copySync(resolve(__dirname, 'node_modules_rename_me'), resolve(__dirname, 'node_modules')); runTestSuiteWithSamples( 'cli', - path.resolve(__dirname, 'samples'), + resolve(__dirname, 'samples'), (dir, config) => { // allow to repeat flaky tests for debugging on CLI for (let pass = 0; pass < (config.repeat || 1); pass++) { @@ -27,7 +29,7 @@ runTestSuiteWithSamples( ); function runTest(dir, config, pass) { - const name = path.basename(dir) + ': ' + config.description; + const name = basename(dir) + ': ' + config.description; (config.skip ? it.skip : config.solo ? it.only : it)( pass > 0 ? `${name} (pass ${pass + 1})` : name, done => { @@ -37,7 +39,7 @@ function runTest(dir, config, pass) { } const command = config.command.replace( /(^| )rollup($| )/g, - `node ${path.resolve(__dirname, '../../dist/bin')}${path.sep}rollup ` + `node ${resolve(__dirname, '../../dist/bin')}${sep}rollup ` ); Promise.resolve(config.before && config.before()).then(() => { @@ -111,10 +113,7 @@ function runTest(dir, config, pass) { } catch (err) { done(err); } - } else if ( - sander.existsSync('_expected') && - sander.statSync('_expected').isDirectory() - ) { + } else if (existsSync('_expected') && statSync('_expected').isDirectory()) { try { assertDirectoriesAreEqual('_actual', '_expected'); done(); @@ -122,7 +121,7 @@ function runTest(dir, config, pass) { done(err); } } else { - const expected = sander.readFileSync('_expected.js').toString(); + const expected = readFileSync('_expected.js', 'utf8'); try { assert.equal(normaliseOutput(code), normaliseOutput(expected)); done(); diff --git a/test/cli/samples/config-no-output/_config.js b/test/cli/samples/config-no-output/_config.js index 148b688c86b..1f0696157c2 100644 --- a/test/cli/samples/config-no-output/_config.js +++ b/test/cli/samples/config-no-output/_config.js @@ -1,12 +1,12 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync, unlinkSync } = require('fs'); module.exports = { description: 'uses -o from CLI', command: 'rollup -c -o output.js', test() { - const output = fs.readFileSync('output.js', 'utf-8'); + const output = readFileSync('output.js', 'utf-8'); assert.equal(output.trim(), 'console.log(42);'); - fs.unlinkSync('output.js'); + unlinkSync('output.js'); } }; diff --git a/test/cli/samples/sourcemap-hidden/_config.js b/test/cli/samples/sourcemap-hidden/_config.js index 6bd4d61f101..5dd0871d5a0 100644 --- a/test/cli/samples/sourcemap-hidden/_config.js +++ b/test/cli/samples/sourcemap-hidden/_config.js @@ -1,16 +1,16 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync, unlinkSync } = require('fs'); module.exports = { description: 'omits sourcemap comments', command: 'rollup -i main.js -f es -m hidden -o output.js', test() { - assert.equal(fs.readFileSync('output.js', 'utf-8').trim(), 'console.log( 42 );'); - fs.unlinkSync('output.js'); + assert.equal(readFileSync('output.js', 'utf-8').trim(), 'console.log( 42 );'); + unlinkSync('output.js'); assert.equal( - fs.readFileSync('output.js.map', 'utf-8').trim(), + readFileSync('output.js.map', 'utf-8').trim(), '{"version":3,"file":"output.js","sources":["main.js"],"sourcesContent":["console.log( 42 );\\n"],"names":[],"mappings":"AAAA,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE"}' ); - fs.unlinkSync('output.js.map'); + unlinkSync('output.js.map'); } }; diff --git a/test/cli/samples/wait-for-bundle-input-object/_config.js b/test/cli/samples/wait-for-bundle-input-object/_config.js index 4bda6e35d5c..dfc50422854 100644 --- a/test/cli/samples/wait-for-bundle-input-object/_config.js +++ b/test/cli/samples/wait-for-bundle-input-object/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { unlinkSync } = require('fs'); const path = require('path'); const { atomicWriteFileSync } = require('../../../utils'); @@ -13,8 +13,8 @@ module.exports = { third = path.resolve(__dirname, 'third.js'); }, after() { - fs.unlinkSync(second); - fs.unlinkSync(third); + unlinkSync(second); + unlinkSync(third); }, abortOnStderr(data) { if (data.includes('waiting for input second')) { diff --git a/test/cli/samples/wait-for-bundle-input/_config.js b/test/cli/samples/wait-for-bundle-input/_config.js index e27820f5bb6..26a18263b2b 100644 --- a/test/cli/samples/wait-for-bundle-input/_config.js +++ b/test/cli/samples/wait-for-bundle-input/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { unlinkSync } = require('fs'); const path = require('path'); const { atomicWriteFileSync } = require('../../../utils'); @@ -11,7 +11,7 @@ module.exports = { mainFile = path.resolve(__dirname, 'main.js'); }, after() { - fs.unlinkSync(mainFile); + unlinkSync(mainFile); }, abortOnStderr(data) { if (data.includes('waiting for input main.js')) { diff --git a/test/cli/samples/warn-broken-sourcemap/_config.js b/test/cli/samples/warn-broken-sourcemap/_config.js index 44597f2d557..7ec82baaf01 100644 --- a/test/cli/samples/warn-broken-sourcemap/_config.js +++ b/test/cli/samples/warn-broken-sourcemap/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { unlinkSync } = require('fs'); const path = require('path'); const { assertIncludes } = require('../../../utils.js'); @@ -6,8 +6,8 @@ module.exports = { description: 'displays warnings for broken sourcemaps', command: 'rollup -c', stderr: stderr => { - fs.unlinkSync(path.resolve(__dirname, 'bundle')); - fs.unlinkSync(path.resolve(__dirname, 'bundle.map')); + unlinkSync(path.resolve(__dirname, 'bundle')); + unlinkSync(path.resolve(__dirname, 'bundle.map')); assertIncludes( stderr, '(!) Broken sourcemap\n' + diff --git a/test/cli/samples/warn-broken-sourcemaps/_config.js b/test/cli/samples/warn-broken-sourcemaps/_config.js index b3e2e2ba768..a6aafd97a38 100644 --- a/test/cli/samples/warn-broken-sourcemaps/_config.js +++ b/test/cli/samples/warn-broken-sourcemaps/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { unlinkSync } = require('fs'); const path = require('path'); const { assertIncludes } = require('../../../utils.js'); @@ -6,8 +6,8 @@ module.exports = { description: 'displays warnings for broken sourcemaps', command: 'rollup -c', stderr: stderr => { - fs.unlinkSync(path.resolve(__dirname, 'bundle')); - fs.unlinkSync(path.resolve(__dirname, 'bundle.map')); + unlinkSync(path.resolve(__dirname, 'bundle')); + unlinkSync(path.resolve(__dirname, 'bundle.map')); assertIncludes( stderr, '(!) Broken sourcemap\n' + diff --git a/test/cli/samples/watch/bundle-error/_config.js b/test/cli/samples/watch/bundle-error/_config.js index 2f38a2e2407..25046a7f5f1 100644 --- a/test/cli/samples/watch/bundle-error/_config.js +++ b/test/cli/samples/watch/bundle-error/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { unlinkSync, writeFileSync } = require('fs'); const path = require('path'); const { atomicWriteFileSync } = require('../../../../utils'); @@ -9,11 +9,11 @@ module.exports = { command: 'rollup -cw', before() { mainFile = path.resolve(__dirname, 'main.js'); - fs.writeFileSync(mainFile, '<=>'); + writeFileSync(mainFile, '<=>'); }, after() { // synchronous sometimes does not seem to work, probably because the watch is not yet removed properly - setTimeout(() => fs.unlinkSync(mainFile), 300); + setTimeout(() => unlinkSync(mainFile), 300); }, abortOnStderr(data) { if (data.includes('Error: Unexpected token')) { diff --git a/test/cli/samples/watch/close-stdin/wrapper.js b/test/cli/samples/watch/close-stdin/wrapper.js index a978de79c4b..32506153c5d 100755 --- a/test/cli/samples/watch/close-stdin/wrapper.js +++ b/test/cli/samples/watch/close-stdin/wrapper.js @@ -1,7 +1,7 @@ #!/usr/bin/env node const stream = require('stream'); -const fs = require('fs'); +const { mkdirSync, readFileSync, writeFileSync } = require('fs'); const chokidar = require('chokidar'); const path = require('path'); @@ -14,13 +14,13 @@ process.stdin = new stream.Readable({ }); const outputDir = path.resolve(__dirname, '_actual'); -fs.mkdirSync(outputDir); +mkdirSync(outputDir); const outputFile = path.resolve(outputDir, 'out.js'); const INITIAL_OUTPUT = 'NOT WRITTEN'; -fs.writeFileSync(outputFile, INITIAL_OUTPUT); +writeFileSync(outputFile, INITIAL_OUTPUT); const watcher = chokidar.watch(outputFile).on('change', () => { - if (fs.readFileSync(outputFile, 'utf8') !== INITIAL_OUTPUT) { + if (readFileSync(outputFile, 'utf8') !== INITIAL_OUTPUT) { watcher.close(); // This closes stdin process.stdin.push(null); diff --git a/test/cli/samples/watch/watch-config-early-update/_config.js b/test/cli/samples/watch/watch-config-early-update/_config.js index 031d5d38d14..3af6f00847f 100644 --- a/test/cli/samples/watch/watch-config-early-update/_config.js +++ b/test/cli/samples/watch/watch-config-early-update/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { mkdirSync, unlinkSync } = require('fs'); const path = require('path'); const { writeAndSync, writeAndRetry } = require('../../../../utils'); @@ -15,7 +15,7 @@ module.exports = { // parsed. To do that, the first config hooks into process.stderr and looks for a log from the // second config. // That way, we simulate a complicated config file being changed while it is parsed. - fs.mkdirSync(path.join(__dirname, '_actual')); + mkdirSync(path.join(__dirname, '_actual')); writeAndSync( configFile, ` @@ -44,7 +44,7 @@ module.exports = { ); }, after() { - fs.unlinkSync(configFile); + unlinkSync(configFile); }, abortOnStderr(data) { if (data === 'initial\n') { diff --git a/test/cli/samples/watch/watch-config-error/_config.js b/test/cli/samples/watch/watch-config-error/_config.js index b313c17851f..15ac4f74345 100644 --- a/test/cli/samples/watch/watch-config-error/_config.js +++ b/test/cli/samples/watch/watch-config-error/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { unlinkSync, writeFileSync } = require('fs'); const path = require('path'); const { atomicWriteFileSync } = require('../../../../utils'); @@ -9,7 +9,7 @@ module.exports = { command: 'rollup -cw', before() { configFile = path.resolve(__dirname, 'rollup.config.js'); - fs.writeFileSync( + writeFileSync( configFile, ` export default { @@ -22,7 +22,7 @@ module.exports = { ); }, after() { - fs.unlinkSync(configFile); + unlinkSync(configFile); }, abortOnStderr(data) { if (data.includes(`created _actual${path.sep}main1.js`)) { diff --git a/test/cli/samples/watch/watch-config-initial-error/_config.js b/test/cli/samples/watch/watch-config-initial-error/_config.js index d2ecd6532ec..7faa10b357a 100644 --- a/test/cli/samples/watch/watch-config-initial-error/_config.js +++ b/test/cli/samples/watch/watch-config-initial-error/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { unlinkSync, writeFileSync } = require('fs'); const path = require('path'); const { atomicWriteFileSync } = require('../../../../utils'); @@ -9,10 +9,10 @@ module.exports = { command: 'rollup -cw', before() { configFile = path.join(__dirname, 'rollup.config.js'); - fs.writeFileSync(configFile, 'throw new Error("Config contains initial errors");'); + writeFileSync(configFile, 'throw new Error("Config contains initial errors");'); }, after() { - fs.unlinkSync(configFile); + unlinkSync(configFile); }, async abortOnStderr(data) { if (data.includes('Config contains initial errors')) { diff --git a/test/cli/samples/watch/watch-config-no-update/_config.js b/test/cli/samples/watch/watch-config-no-update/_config.js index a90cb10e14a..3f8dea95e2c 100644 --- a/test/cli/samples/watch/watch-config-no-update/_config.js +++ b/test/cli/samples/watch/watch-config-no-update/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { unlinkSync, writeFileSync } = require('fs'); const path = require('path'); const { atomicWriteFileSync } = require('../../../../utils'); @@ -17,10 +17,10 @@ module.exports = { command: 'rollup -cw', before() { configFile = path.resolve(__dirname, 'rollup.config.js'); - fs.writeFileSync(configFile, configContent); + writeFileSync(configFile, configContent); }, after() { - fs.unlinkSync(configFile); + unlinkSync(configFile); }, abortOnStderr(data) { if (data.includes(`created _actual${path.sep}main.js`)) { diff --git a/test/form/index.js b/test/form/index.js index 928a9cdd641..f0d1c6e4145 100644 --- a/test/form/index.js +++ b/test/form/index.js @@ -1,13 +1,13 @@ const assert = require('assert'); +const { existsSync, readFileSync } = require('fs'); const path = require('path'); -const sander = require('sander'); const rollup = require('../../dist/rollup'); const { normaliseOutput, runTestSuiteWithSamples } = require('../utils.js'); const FORMATS = ['amd', 'cjs', 'system', 'es', 'iife', 'umd']; runTestSuiteWithSamples('form', path.resolve(__dirname, 'samples'), (dir, config) => { - const isSingleFormatTest = sander.existsSync(dir + '/_expected.js'); + const isSingleFormatTest = existsSync(dir + '/_expected.js'); const itOrDescribe = isSingleFormatTest ? it : describe; (config.skip ? itOrDescribe.skip : config.solo ? itOrDescribe.only : itOrDescribe)( path.basename(dir) + ': ' + config.description, @@ -79,19 +79,19 @@ runTestSuiteWithSamples('form', path.resolve(__dirname, 'samples'), (dir, config async function generateAndTestBundle(bundle, outputOptions, expectedFile, { show }) { await bundle.write(outputOptions); - const actualCode = normaliseOutput(sander.readFileSync(outputOptions.file)); + const actualCode = normaliseOutput(readFileSync(outputOptions.file, 'utf8')); let expectedCode; let actualMap; let expectedMap; try { - expectedCode = normaliseOutput(sander.readFileSync(expectedFile)); + expectedCode = normaliseOutput(readFileSync(expectedFile, 'utf8')); } catch (err) { expectedCode = 'missing file'; } try { - actualMap = JSON.parse(sander.readFileSync(outputOptions.file + '.map').toString()); + actualMap = JSON.parse(readFileSync(outputOptions.file + '.map', 'utf8')); actualMap.sourcesContent = actualMap.sourcesContent ? actualMap.sourcesContent.map(normaliseOutput) : null; @@ -100,7 +100,7 @@ async function generateAndTestBundle(bundle, outputOptions, expectedFile, { show } try { - expectedMap = JSON.parse(sander.readFileSync(expectedFile + '.map').toString()); + expectedMap = JSON.parse(readFileSync(expectedFile + '.map', 'utf8')); expectedMap.sourcesContent = actualMap.sourcesContent ? expectedMap.sourcesContent.map(normaliseOutput) : null; diff --git a/test/form/samples/deprecated/emit-asset/_config.js b/test/form/samples/deprecated/emit-asset/_config.js index 6d4c88ac239..f7930b32270 100644 --- a/test/form/samples/deprecated/emit-asset/_config.js +++ b/test/form/samples/deprecated/emit-asset/_config.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); module.exports = { @@ -17,7 +17,7 @@ module.exports = { if (id.endsWith('.svg')) { return `export default import.meta.ROLLUP_ASSET_URL_${this.emitAsset( path.basename(id), - fs.readFileSync(id) + readFileSync(id) )};`; } }, @@ -30,7 +30,7 @@ module.exports = { assert.strictEqual(asset.isAsset, true); assert.strictEqual(asset.type, 'asset'); assert.ok( - asset.source.equals(fs.readFileSync(path.resolve(__dirname, 'logo.svg'))), + asset.source.equals(readFileSync(path.resolve(__dirname, 'logo.svg'))), 'asset has correct source' ); assert.ok(keys[1].endsWith('.js'), `${keys[1]} ends with ".js"`); diff --git a/test/form/samples/emit-asset-file/_config.js b/test/form/samples/emit-asset-file/_config.js index 5976fabd374..b4bbd8926d7 100644 --- a/test/form/samples/emit-asset-file/_config.js +++ b/test/form/samples/emit-asset-file/_config.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); module.exports = { @@ -16,7 +16,7 @@ module.exports = { return `export default import.meta.ROLLUP_FILE_URL_${this.emitFile({ type: 'asset', name: path.basename(id), - source: fs.readFileSync(id) + source: readFileSync(id) })};`; } }, @@ -28,7 +28,7 @@ module.exports = { assert.strictEqual(asset.fileName, 'assets/logo-25585ac1.svg'); assert.strictEqual(asset.type, 'asset'); assert.ok( - asset.source.equals(fs.readFileSync(path.resolve(__dirname, 'logo.svg'))), + asset.source.equals(readFileSync(path.resolve(__dirname, 'logo.svg'))), 'asset has correct source' ); assert.ok(keys[1].endsWith('.js'), `${keys[1]} ends with ".js"`); diff --git a/test/form/samples/emit-file-tree-shaken-access/_config.js b/test/form/samples/emit-file-tree-shaken-access/_config.js index 1feae6664f4..3b52af0c675 100644 --- a/test/form/samples/emit-file-tree-shaken-access/_config.js +++ b/test/form/samples/emit-file-tree-shaken-access/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); module.exports = { @@ -15,7 +15,7 @@ module.exports = { return `export default import.meta.ROLLUP_FILE_URL_${this.emitFile({ type: 'asset', name: path.basename(id), - source: fs.readFileSync(id) + source: readFileSync(id) })};`; } } diff --git a/test/function/samples/custom-loaders/_config.js b/test/function/samples/custom-loaders/_config.js index e2f0cec12b1..e9e52b0b884 100644 --- a/test/function/samples/custom-loaders/_config.js +++ b/test/function/samples/custom-loaders/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { readFileSync } = require('fs'); module.exports = { description: 'uses custom loaders, falling back to default', @@ -7,14 +7,14 @@ module.exports = { { load(id) { if (/foo\.js/.test(id)) { - return fs.readFileSync(id, 'utf-8').replace('@', 1); + return readFileSync(id, 'utf-8').replace('@', 1); } } }, { load(id) { if (/bar\.js/.test(id)) { - return fs.readFileSync(id, 'utf-8').replace('@', 2); + return readFileSync(id, 'utf-8').replace('@', 2); } } } diff --git a/test/function/samples/custom-path-resolver-on-entry/_config.js b/test/function/samples/custom-path-resolver-on-entry/_config.js index 7d49020fd95..c92be833424 100644 --- a/test/function/samples/custom-path-resolver-on-entry/_config.js +++ b/test/function/samples/custom-path-resolver-on-entry/_config.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); const cachedModules = { @@ -25,7 +25,7 @@ module.exports = { return cachedModules[moduleId]; } - return fs.readFileSync(moduleId, 'utf-8'); + return readFileSync(moduleId, 'utf-8'); } } ] diff --git a/test/function/samples/export-default-anonymous-function/_config.js b/test/function/samples/export-default-anonymous-function/_config.js index 030af6269a7..14a8ec085be 100644 --- a/test/function/samples/export-default-anonymous-function/_config.js +++ b/test/function/samples/export-default-anonymous-function/_config.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); module.exports = { @@ -10,7 +10,7 @@ module.exports = { return path.basename(importee).replace(/\..+/, ''); }, load(id) { - return fs.readFileSync(path.join(__dirname, id + '.js'), 'utf-8'); + return readFileSync(path.join(__dirname, id + '.js'), 'utf-8'); } } ] diff --git a/test/function/samples/transform-without-code/_config.js b/test/function/samples/transform-without-code/_config.js index dc9d1447d13..cfe8d21e839 100644 --- a/test/function/samples/transform-without-code/_config.js +++ b/test/function/samples/transform-without-code/_config.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); const { SourceMapConsumer } = require('source-map'); @@ -21,7 +21,7 @@ module.exports = { const smc = await new SourceMapConsumer(map); const originalLoc = smc.originalPositionFor({ line, column }); assert.notStrictEqual(originalLoc.line, null); - const originalCode = fs.readFileSync(path.join(__dirname, 'main.js'), 'utf8'); + const originalCode = readFileSync(path.join(__dirname, 'main.js'), 'utf8'); assert.strictEqual( originalCode.split('\n')[originalLoc.line - 1].substr(originalLoc.column, 2), '42' diff --git a/test/hooks/index.js b/test/hooks/index.js index d0f04609ae1..b776bb9e808 100644 --- a/test/hooks/index.js +++ b/test/hooks/index.js @@ -1,6 +1,7 @@ const assert = require('assert'); +const { readdirSync } = require('fs'); const path = require('path'); -const sander = require('sander'); +const { removeSync } = require('fs-extra'); const rollup = require('../../dist/rollup.js'); const { loader } = require('../utils.js'); @@ -33,9 +34,9 @@ describe('hooks', () => { }) ) .then(() => { - const fileNames = sander.readdirSync(TEMP_DIR).sort(); + const fileNames = readdirSync(TEMP_DIR).sort(); assert.deepStrictEqual(fileNames, ['chunk.js', 'input.js']); - return sander.rimraf(TEMP_DIR); + return removeSync(TEMP_DIR); })); it('supports buildStart and buildEnd hooks', () => { @@ -574,7 +575,7 @@ describe('hooks', () => { .then(bundle => bundle.write({ format: 'es', file })) .then(() => { assert.strictEqual(callCount, 1); - return sander.rimraf(TEMP_DIR); + return removeSync(TEMP_DIR); }); }); diff --git a/test/sourcemaps/samples/combined-sourcemap-with-loader/_config.js b/test/sourcemaps/samples/combined-sourcemap-with-loader/_config.js index 1f670313146..c9d16748ce3 100644 --- a/test/sourcemaps/samples/combined-sourcemap-with-loader/_config.js +++ b/test/sourcemaps/samples/combined-sourcemap-with-loader/_config.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync } = require('fs'); const buble = require('buble'); const MagicString = require('magic-string'); const { SourceMapConsumer } = require('source-map'); @@ -11,7 +11,7 @@ module.exports = { plugins: [ { load(id) { - const code = fs.readFileSync(id, 'utf-8'); + const code = readFileSync(id, 'utf-8'); const out = buble.transform(code, { transforms: { modules: false }, sourceMap: true, diff --git a/test/sourcemaps/samples/excludes-plugin-helpers/_config.js b/test/sourcemaps/samples/excludes-plugin-helpers/_config.js index 393c9e825a3..e64a91e702f 100644 --- a/test/sourcemaps/samples/excludes-plugin-helpers/_config.js +++ b/test/sourcemaps/samples/excludes-plugin-helpers/_config.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); const HELPER = '\0helper'; @@ -18,7 +18,7 @@ module.exports = { load(id) { if (id === HELPER) { - return fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8'); + return readFileSync(path.join(__dirname, 'helper.js'), 'utf-8'); } } } diff --git a/test/sourcemaps/samples/loaders/_config.js b/test/sourcemaps/samples/loaders/_config.js index 9e45fa58ec9..7df0a3b4fef 100644 --- a/test/sourcemaps/samples/loaders/_config.js +++ b/test/sourcemaps/samples/loaders/_config.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync } = require('fs'); const buble = require('buble'); const { SourceMapConsumer } = require('source-map'); const getLocation = require('../../getLocation'); @@ -16,7 +16,7 @@ module.exports = { id = id.replace(/bar.js$/, 'foo.js'); } - const code = fs.readFileSync(id, 'utf-8'); + const code = readFileSync(id, 'utf-8'); const out = buble.transform(code, { transforms: { modules: false }, diff --git a/test/sourcemaps/samples/reified-namespace/_config.js b/test/sourcemaps/samples/reified-namespace/_config.js index 431758d276a..09fd70e39f5 100644 --- a/test/sourcemaps/samples/reified-namespace/_config.js +++ b/test/sourcemaps/samples/reified-namespace/_config.js @@ -1,5 +1,5 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); const { SourceMapConsumer } = require('source-map'); const getLocation = require('../../getLocation'); @@ -9,7 +9,7 @@ module.exports = { async test(code, map) { const smc = await new SourceMapConsumer(map); - const main = fs.readFileSync(path.join(__dirname, 'main.js'), 'utf-8'); + const main = readFileSync(path.join(__dirname, 'main.js'), 'utf-8'); const generatedLoc = getLocation(code, 'deepEqual'); const actual = smc.originalPositionFor(generatedLoc); diff --git a/test/sourcemaps/samples/single-length-segments/_config.js b/test/sourcemaps/samples/single-length-segments/_config.js index 1b38deb956d..7850b91ad7a 100644 --- a/test/sourcemaps/samples/single-length-segments/_config.js +++ b/test/sourcemaps/samples/single-length-segments/_config.js @@ -1,10 +1,10 @@ const assert = require('assert'); -const fs = require('fs'); +const { readFileSync } = require('fs'); const path = require('path'); const { SourceMapConsumer } = require('source-map'); const getLocation = require('../../getLocation'); -const original = fs.readFileSync(path.resolve(__dirname, 'main.js'), 'utf-8'); +const original = readFileSync(path.resolve(__dirname, 'main.js'), 'utf-8'); module.exports = { description: 'handles single-length sourcemap segments', @@ -13,8 +13,8 @@ module.exports = { { transform() { return { - code: fs.readFileSync(path.resolve(__dirname, 'output.js'), 'utf-8'), - map: fs.readFileSync(path.resolve(__dirname, 'output.js.map'), 'utf-8') + code: readFileSync(path.resolve(__dirname, 'output.js'), 'utf-8'), + map: readFileSync(path.resolve(__dirname, 'output.js.map'), 'utf-8') }; } } diff --git a/test/utils.js b/test/utils.js index 7d391538477..57854e5c41c 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,8 +1,18 @@ const assert = require('assert'); -const fs = require('fs'); -const path = require('path'); +const { + closeSync, + fsyncSync, + openSync, + readdirSync, + renameSync, + unlinkSync, + writeFileSync, + writeSync +} = require('fs'); +const { basename, join } = require('path'); +const { platform, version } = require('process'); const fixturify = require('fixturify'); -const sander = require('sander'); +const { removeSync } = require('fs-extra'); exports.compareError = compareError; exports.compareWarnings = compareWarnings; @@ -124,11 +134,11 @@ function runSamples(samplesDir, runTest, onTeardown) { if (onTeardown) { afterEach(onTeardown); } - sander - .readdirSync(samplesDir) + + readdirSync(samplesDir) .filter(name => name[0] !== '.') .sort() - .forEach(fileName => runTestsInDir(path.join(samplesDir, fileName), runTest)); + .forEach(fileName => runTestsInDir(join(samplesDir, fileName), runTest)); } function runTestsInDir(dir, runTest) { @@ -137,26 +147,26 @@ function runTestsInDir(dir, runTest) { loadConfigAndRunTest(dir, runTest); } else if (fileNames.length === 0) { console.warn(`Removing empty test directory ${dir}`); - sander.rmdirSync(dir); + removeSync(dir); } else { - describe(path.basename(dir), () => { + describe(basename(dir), () => { fileNames .filter(name => name[0] !== '.') .sort() - .forEach(fileName => runTestsInDir(path.join(dir, fileName), runTest)); + .forEach(fileName => runTestsInDir(join(dir, fileName), runTest)); }); } } function getFileNamesAndRemoveOutput(dir) { try { - return sander.readdirSync(dir).filter(fileName => { + return readdirSync(dir).filter(fileName => { if (fileName === '_actual') { - sander.rimrafSync(path.join(dir, '_actual')); + removeSync(join(dir, '_actual')); return false; } if (fileName === '_actual.js') { - sander.unlinkSync(path.join(dir, '_actual.js')); + unlinkSync(join(dir, '_actual.js')); return false; } return true; @@ -172,15 +182,15 @@ function getFileNamesAndRemoveOutput(dir) { } function loadConfigAndRunTest(dir, runTest) { - const configFile = path.join(dir, '_config.js'); + const configFile = join(dir, '_config.js'); const config = require(configFile); if (!config || !config.description) { throw new Error(`Found invalid config without description: ${configFile}`); } if ( - (!config.skipIfWindows || process.platform !== 'win32') && - (!config.onlyWindows || process.platform === 'win32') && - (!config.minNodeVersion || config.minNodeVersion <= Number(/^v(\d+)/.exec(process.version)[1])) + (!config.skipIfWindows || platform !== 'win32') && + (!config.onlyWindows || platform === 'win32') && + (!config.minNodeVersion || config.minNodeVersion <= Number(/^v(\d+)/.exec(version)[1])) ) { runTest(dir, config); } @@ -231,16 +241,16 @@ function assertIncludes(actual, expected) { // if the content being overwritten is identical. function atomicWriteFileSync(filePath, contents) { const stagingPath = filePath + '_'; - fs.writeFileSync(stagingPath, contents); - fs.renameSync(stagingPath, filePath); + writeFileSync(stagingPath, contents); + renameSync(stagingPath, filePath); } // It appears that on MacOS, it sometimes takes long for the file system to update function writeAndSync(filePath, contents) { - const file = fs.openSync(filePath, 'w'); - fs.writeSync(file, contents); - fs.fsyncSync(file); - fs.closeSync(file); + const file = openSync(filePath, 'w'); + writeSync(file, contents); + fsyncSync(file); + closeSync(file); } // Sometimes, watchers on MacOS do not seem to fire. In those cases, it helps diff --git a/test/watch/index.js b/test/watch/index.js index 64b66b5cb97..648f3e819b7 100644 --- a/test/watch/index.js +++ b/test/watch/index.js @@ -1,11 +1,18 @@ const assert = require('assert'); -const path = require('path'); -const sander = require('sander'); +const { + existsSync, + promises, + readdirSync, + readFileSync, + unlinkSync, + writeFileSync +} = require('fs'); +const { resolve } = require('path'); +const { chdir, cwd, hrtime } = require('process'); +const { copy, removeSync } = require('fs-extra'); const rollup = require('../../dist/rollup'); const { atomicWriteFileSync } = require('../utils'); -const cwd = process.cwd(); - function wait(ms) { return new Promise(fulfil => { setTimeout(fulfil, ms); @@ -16,8 +23,8 @@ describe('rollup.watch', () => { let watcher; beforeEach(() => { - process.chdir(cwd); - return sander.rimraf('test/_tmp'); + chdir(cwd()); + return removeSync('test/_tmp'); }); afterEach(() => { @@ -68,118 +75,112 @@ describe('rollup.watch', () => { } function getTimeDiffInMs(previous) { - const [seconds, nanoseconds] = process.hrtime(previous); + const [seconds, nanoseconds] = hrtime(previous); return seconds * 1e3 + nanoseconds / 1e6; } it('watches a file and triggers reruns if necessary', () => { let triggerRestart = false; - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - options(options) { - assert.strictEqual(this.meta.watchMode, true, 'watchMode in options'); - }, - transform(code) { - assert.strictEqual(this.meta.watchMode, true, 'watchMode in transform'); - if (triggerRestart) { - triggerRestart = false; - return wait(100) - .then(() => atomicWriteFileSync('test/_tmp/input/main.js', 'export default 44;')) - .then(() => wait(100)) - .then(() => code); - } - } - }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - triggerRestart = true; - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + options() { + assert.strictEqual(this.meta.watchMode, true, 'watchMode in options'); }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 44); + transform(code) { + assert.strictEqual(this.meta.watchMode, true, 'watchMode in transform'); + if (triggerRestart) { + triggerRestart = false; + return wait(100) + .then(() => atomicWriteFileSync('test/_tmp/input/main.js', 'export default 44;')) + .then(() => wait(100)) + .then(() => code); + } } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + triggerRestart = true; + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 44); + } + ]); + }); }); it('does not fail for virtual files', () => { - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - resolveId(id) { - if (id === 'virtual') { - return id; - } - }, - load(id) { - if (id === 'virtual') { - return `export const value = 42;`; - } + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + resolveId(id) { + if (id === 'virtual') { + return id; } }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - atomicWriteFileSync( - 'test/_tmp/input/main.js', - "import {value} from 'virtual';\nexport default value + 1;" - ); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + load(id) { + if (id === 'virtual') { + return `export const value = 42;`; + } } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + atomicWriteFileSync( + 'test/_tmp/input/main.js', + "import {value} from 'virtual';\nexport default value + 1;" + ); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); + }); }); it('passes file events to the watchChange plugin hook once for each change', async () => { let watchChangeCnt = 0; - await sander.copydir('test/watch/samples/basic').to('test/_tmp/input'); + await copy('test/watch/samples/basic', 'test/_tmp/input'); await wait(100); watcher = rollup.watch({ input: 'test/_tmp/input/main.js', @@ -191,7 +192,7 @@ describe('rollup.watch', () => { plugins: { watchChange(id) { watchChangeCnt++; - assert.strictEqual(id, path.resolve('test/_tmp/input/main.js')); + assert.strictEqual(id, resolve('test/_tmp/input/main.js')); } } }); @@ -236,12 +237,12 @@ describe('rollup.watch', () => { }); it('passes change parameter to the watchChange plugin hook', async () => { - const WATCHED_ID = path.resolve('test/_tmp/input/watched'); + const WATCHED_ID = resolve('test/_tmp/input/watched'); const events = []; let ids; - const expectedIds = [WATCHED_ID, path.resolve('test/_tmp/input/main.js')]; - await sander.copydir('test/watch/samples/watch-files').to('test/_tmp/input'); - await sander.unlink(WATCHED_ID); + const expectedIds = [WATCHED_ID, resolve('test/_tmp/input/main.js')]; + await copy('test/watch/samples/watch-files', 'test/_tmp/input'); + await promises.unlink(WATCHED_ID); await wait(100); watcher = rollup.watch({ input: 'test/_tmp/input/main.js', @@ -296,7 +297,7 @@ describe('rollup.watch', () => { assert.strictEqual(run('../_tmp/output/bundle.js'), 42); assert.deepStrictEqual(events, ['create', 'update']); assert.deepStrictEqual(ids, expectedIds); - sander.unlinkSync(WATCHED_ID); + unlinkSync(WATCHED_ID); }, 'START', 'BUNDLE_START', @@ -311,10 +312,10 @@ describe('rollup.watch', () => { }); it('correctly rewrites change event during build delay', async () => { - const WATCHED_ID = path.resolve('test/_tmp/input/watched'); - const MAIN_ID = path.resolve('test/_tmp/input/main.js'); + const WATCHED_ID = resolve('test/_tmp/input/watched'); + const MAIN_ID = resolve('test/_tmp/input/main.js'); let lastEvent = null; - await sander.copydir('test/watch/samples/watch-files').to('test/_tmp/input'); + await copy('test/watch/samples/watch-files', 'test/_tmp/input'); await wait(100); watcher = rollup.watch({ input: 'test/_tmp/input/main.js', @@ -351,7 +352,7 @@ describe('rollup.watch', () => { assert.strictEqual(lastEvent, null); atomicWriteFileSync(WATCHED_ID, 'another'); await wait(100); - sander.unlinkSync(WATCHED_ID); + unlinkSync(WATCHED_ID); }, 'START', 'BUNDLE_START', @@ -362,7 +363,7 @@ describe('rollup.watch', () => { lastEvent = null; atomicWriteFileSync(WATCHED_ID, '123'); await wait(100); - sander.unlinkSync(WATCHED_ID); + unlinkSync(WATCHED_ID); // To ensure there is always another change to trigger a rebuild atomicWriteFileSync(MAIN_ID, 'export default 43;'); }, @@ -390,589 +391,545 @@ describe('rollup.watch', () => { let calls = 0; let ctx1; let ctx2; - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: [ + { + buildStart() { + ctx1 = this; + }, + closeWatcher() { + assert.strictEqual(ctx1, this); + calls++; + } }, - plugins: [ - { - buildStart() { - ctx1 = this; - }, - closeWatcher() { - assert.strictEqual(ctx1, this); - calls++; - } + { + buildStart() { + ctx2 = this; }, - { - buildStart() { - ctx2 = this; - }, - closeWatcher() { - assert.strictEqual(ctx2, this); - calls++; - } + closeWatcher() { + assert.strictEqual(ctx2, this); + calls++; } - ] - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - assert.ok(ctx1); - assert.ok(ctx2); - watcher.once('close', () => { - assert.strictEqual(calls, 2); - }); - watcher.close(); } - ]); + ] }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + assert.ok(ctx1); + assert.ok(ctx2); + watcher.once('close', () => { + assert.strictEqual(calls, 2); + }); + watcher.close(); + } + ]); + }); }); it('watches a file in code-splitting mode', () => { - return sander - .copydir('test/watch/samples/code-splitting') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: ['test/_tmp/input/main1.js', 'test/_tmp/input/main2.js'], - output: { - dir: 'test/_tmp/output', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/main1.js'), 21); - assert.strictEqual(run('../_tmp/output/main2.js'), 42); - atomicWriteFileSync('test/_tmp/input/shared.js', 'export const value = 22;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/main1.js'), 22); - assert.strictEqual(run('../_tmp/output/main2.js'), 44); - } - ]); + return copy('test/watch/samples/code-splitting', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: ['test/_tmp/input/main1.js', 'test/_tmp/input/main2.js'], + output: { + dir: 'test/_tmp/output', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/main1.js'), 21); + assert.strictEqual(run('../_tmp/output/main2.js'), 42); + atomicWriteFileSync('test/_tmp/input/shared.js', 'export const value = 22;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/main1.js'), 22); + assert.strictEqual(run('../_tmp/output/main2.js'), 44); + } + ]); + }); }); it('watches a file in code-splitting mode with an input object', () => { - return sander - .copydir('test/watch/samples/code-splitting') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: { - _main_1: 'test/_tmp/input/main1.js', - 'subfolder/_main_2': 'test/_tmp/input/main2.js' - }, - output: { - dir: 'test/_tmp/output', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/_main_1.js'), 21); - assert.strictEqual(run('../_tmp/output/subfolder/_main_2.js'), 42); - atomicWriteFileSync('test/_tmp/input/shared.js', 'export const value = 22;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/_main_1.js'), 22); - assert.strictEqual(run('../_tmp/output/subfolder/_main_2.js'), 44); - } - ]); + return copy('test/watch/samples/code-splitting', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: { + _main_1: 'test/_tmp/input/main1.js', + 'subfolder/_main_2': 'test/_tmp/input/main2.js' + }, + output: { + dir: 'test/_tmp/output', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/_main_1.js'), 21); + assert.strictEqual(run('../_tmp/output/subfolder/_main_2.js'), 42); + atomicWriteFileSync('test/_tmp/input/shared.js', 'export const value = 22;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/_main_1.js'), 22); + assert.strictEqual(run('../_tmp/output/subfolder/_main_2.js'), 44); + } + ]); + }); }); it('recovers from an error', () => { - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - atomicWriteFileSync('test/_tmp/input/main.js', 'export nope;'); - }, - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - } - ]); + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); - }); - it('recovers from an error on initial build', () => { - return sander - .copydir('test/watch/samples/error') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + atomicWriteFileSync('test/_tmp/input/main.js', 'export nope;'); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); + }); + }); - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - assert.strictEqual(sander.existsSync('../_tmp/output/bundle.js'), false); - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - } - ]); + it('recovers from an error on initial build', () => { + return copy('test/watch/samples/error', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); + }); }); it('recovers from a plugin error on initial build', () => { let count = 0; - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - transform() { - if (count++ === 0) { - this.error('The first run failed, try again.'); - } + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + transform() { + if (count++ === 0) { + this.error('The first run failed, try again.'); } - }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - assert.strictEqual(sander.existsSync('../_tmp/output/bundle.js'), false); - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); + }); }); it('recovers from an error even when erroring entry was "renamed" (#38)', () => { - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - sander.unlinkSync('test/_tmp/input/main.js'); - atomicWriteFileSync('test/_tmp/input/main.js', 'export nope;'); - }, - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - sander.unlinkSync('test/_tmp/input/main.js'); - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - } - ]); + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + unlinkSync('test/_tmp/input/main.js'); + atomicWriteFileSync('test/_tmp/input/main.js', 'export nope;'); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + unlinkSync('test/_tmp/input/main.js'); + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); + }); }); it('recovers from an error even when erroring dependency was "renamed" (#38)', () => { - return sander - .copydir('test/watch/samples/dependency') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - sander.unlinkSync('test/_tmp/input/dep.js'); - atomicWriteFileSync('test/_tmp/input/dep.js', 'export nope;'); - }, - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - sander.unlinkSync('test/_tmp/input/dep.js'); - atomicWriteFileSync('test/_tmp/input/dep.js', 'export const value = 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 44); - } - ]); + return copy('test/watch/samples/dependency', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + unlinkSync('test/_tmp/input/dep.js'); + atomicWriteFileSync('test/_tmp/input/dep.js', 'export nope;'); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + unlinkSync('test/_tmp/input/dep.js'); + atomicWriteFileSync('test/_tmp/input/dep.js', 'export const value = 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 44); + } + ]); + }); }); it('handles closing the watcher during a build', () => { - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - load() { - watcher.close(); - } - }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - const events = []; - watcher.on('event', event => events.push(event.code)); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - () => { - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 44;'); - return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + load() { + watcher.close(); } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + const events = []; + watcher.on('event', event => events.push(event.code)); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + () => { + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 44;'); + return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); + } + ]); + }); }); it('handles closing the watcher during a build even if an error occurred', () => { - return sander - .copydir('test/watch/samples/error') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - load() { - watcher.close(); - } - }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - const events = []; - watcher.on('event', event => events.push(event.code)); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - () => { - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 44;'); - return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); + return copy('test/watch/samples/error', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + load() { + watcher.close(); } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); - }); + const events = []; + watcher.on('event', event => events.push(event.code)); - it('stops watching files that are no longer part of the graph', () => { - return sander - .copydir('test/watch/samples/dependency') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + () => { + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 44;'); + return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); + } + ]); + }); + }); - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 42;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - let unexpectedEvent = false; - watcher.once('event', event => { - unexpectedEvent = event; - }); - atomicWriteFileSync('test/_tmp/input/dep.js', '= invalid'); - return wait(400).then(() => assert.strictEqual(unexpectedEvent, false)); - } - ]); + it('stops watching files that are no longer part of the graph', () => { + return copy('test/watch/samples/dependency', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 42;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + let unexpectedEvent = false; + watcher.once('event', event => { + unexpectedEvent = event; + }); + atomicWriteFileSync('test/_tmp/input/dep.js', '= invalid'); + return wait(400).then(() => assert.strictEqual(unexpectedEvent, false)); + } + ]); + }); }); it('refuses to watch the output file (#15)', () => { - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - atomicWriteFileSync('test/_tmp/input/main.js', `import '../output/bundle.js'`); - }, - 'START', - 'BUNDLE_START', - 'ERROR', - event => { - assert.strictEqual(event.error.message, 'Cannot import the generated bundle'); - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - } - ]); + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + atomicWriteFileSync('test/_tmp/input/main.js', `import '../output/bundle.js'`); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + event => { + assert.strictEqual(event.error.message, 'Cannot import the generated bundle'); + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); + }); }); it('ignores files that are not specified in options.watch.include, if given', () => { - return sander - .copydir('test/watch/samples/ignored') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - watch: { - include: ['test/_tmp/input/+(main|foo).js'] - } - }); + return copy('test/watch/samples/ignored', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + watch: { + include: ['test/_tmp/input/+(main|foo).js'] + } + }); - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { - foo: 'foo-1', - bar: 'bar-1' - }); - atomicWriteFileSync('test/_tmp/input/foo.js', `export default 'foo-2';`); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { + foo: 'foo-1', + bar: 'bar-1' + }); + atomicWriteFileSync('test/_tmp/input/foo.js', `export default 'foo-2';`); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { + foo: 'foo-2', + bar: 'bar-1' + }); + let unexpectedEvent = false; + watcher.once('event', event => { + unexpectedEvent = event; + }); + atomicWriteFileSync('test/_tmp/input/bar.js', "export default 'bar-2';"); + return wait(400).then(() => { assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { foo: 'foo-2', bar: 'bar-1' }); - let unexpectedEvent = false; - watcher.once('event', event => { - unexpectedEvent = event; - }); - atomicWriteFileSync('test/_tmp/input/bar.js', "export default 'bar-2';"); - return wait(400).then(() => { - assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { - foo: 'foo-2', - bar: 'bar-1' - }); - assert.strictEqual(unexpectedEvent, false); - }); - } - ]); - }); + assert.strictEqual(unexpectedEvent, false); + }); + } + ]); + }); }); it('ignores files that are specified in options.watch.exclude, if given', () => { - return sander - .copydir('test/watch/samples/ignored') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - watch: { - exclude: ['test/_tmp/input/bar.js'] - } - }); + return copy('test/watch/samples/ignored', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + watch: { + exclude: ['test/_tmp/input/bar.js'] + } + }); - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { - foo: 'foo-1', - bar: 'bar-1' - }); - atomicWriteFileSync('test/_tmp/input/foo.js', `export default 'foo-2';`); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { + foo: 'foo-1', + bar: 'bar-1' + }); + atomicWriteFileSync('test/_tmp/input/foo.js', `export default 'foo-2';`); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { + foo: 'foo-2', + bar: 'bar-1' + }); + let unexpectedEvent = false; + watcher.once('event', event => { + unexpectedEvent = event; + }); + atomicWriteFileSync('test/_tmp/input/bar.js', "export default 'bar-2';"); + return wait(400).then(() => { assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { foo: 'foo-2', bar: 'bar-1' }); - let unexpectedEvent = false; - watcher.once('event', event => { - unexpectedEvent = event; - }); - atomicWriteFileSync('test/_tmp/input/bar.js', "export default 'bar-2';"); - return wait(400).then(() => { - assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { - foo: 'foo-2', - bar: 'bar-1' - }); - assert.strictEqual(unexpectedEvent, false); - }); - } - ]); - }); + assert.strictEqual(unexpectedEvent, false); + }); + } + ]); + }); }); it('only rebuilds the appropriate configs', () => { - return sander - .copydir('test/watch/samples/multiple') - .to('test/_tmp/input') + return copy('test/watch/samples/multiple', 'test/_tmp/input') .then(() => wait(100)) .then(() => { watcher = rollup.watch([ @@ -1019,9 +976,7 @@ describe('rollup.watch', () => { }); it('allows watching only some configs', () => { - return sander - .copydir('test/watch/samples/multiple') - .to('test/_tmp/input') + return copy('test/watch/samples/multiple', 'test/_tmp/input') .then(() => wait(100)) .then(() => { watcher = rollup.watch([ @@ -1050,14 +1005,8 @@ describe('rollup.watch', () => { 'BUNDLE_END', 'END', () => { - assert.strictEqual( - sander.existsSync(path.resolve(__dirname, '../_tmp/output/bundle1.js')), - false - ); - assert.strictEqual( - sander.existsSync(path.resolve(__dirname, '../_tmp/output/bundle2.js')), - true - ); + assert.strictEqual(existsSync(resolve(__dirname, '../_tmp/output/bundle1.js')), false); + assert.strictEqual(existsSync(resolve(__dirname, '../_tmp/output/bundle2.js')), true); assert.deepStrictEqual(run('../_tmp/output/bundle2.js'), 43); } ]); @@ -1065,258 +1014,246 @@ describe('rollup.watch', () => { }); it('respects output.globals', () => { - return sander - .copydir('test/watch/samples/globals') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'iife', - globals: { - jquery: 'jQuery' - } - }, - external: ['jquery'] - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - const generated = sander.readFileSync('test/_tmp/output/bundle.js', { - encoding: 'utf-8' - }); - assert.ok(/jQuery/.test(generated)); + return copy('test/watch/samples/globals', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'iife', + globals: { + jquery: 'jQuery' } - ]); + }, + external: ['jquery'] }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + const generated = readFileSync('test/_tmp/output/bundle.js', { + encoding: 'utf-8' + }); + assert.ok(/jQuery/.test(generated)); + } + ]); + }); }); it('treats filenames literally, not as globs', () => { - return sander - .copydir('test/watch/samples/non-glob') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); + return copy('test/watch/samples/non-glob', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } + }); - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - atomicWriteFileSync('test/_tmp/input/[foo]/bar.js', `export const bar = 43;`); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - } - ]); - }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + atomicWriteFileSync('test/_tmp/input/[foo]/bar.js', `export const bar = 43;`); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); + }); }); it('updates the right hashes on dependency changes', () => { let dynamicName; let staticName; let chunkName; - return sander - .copydir('test/watch/samples/hashing') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: ['test/_tmp/input/main-static.js', 'test/_tmp/input/main-dynamic.js'], - output: { - dir: 'test/_tmp/output', - format: 'cjs', - exports: 'auto', - entryFileNames: '[name].[hash].js', - chunkFileNames: '[name].[hash].js' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - [dynamicName, staticName, chunkName] = sander.readdirSync('test/_tmp/output').sort(); - sander.rimrafSync('test/_tmp/output'); - - // this should only update the hash of that particular entry point - atomicWriteFileSync( - 'test/_tmp/input/main-static.js', - "import {value} from './shared';\nexport default 2 * value;" - ); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - const [newDynamicName, newStaticName, newChunkName] = sander - .readdirSync('test/_tmp/output') - .sort(); - sander.rimrafSync('test/_tmp/output'); - assert.notEqual(newStaticName, staticName); - assert.strictEqual(newDynamicName, dynamicName); - assert.strictEqual(newChunkName, chunkName); - staticName = newStaticName; - - // this should update all hashes - atomicWriteFileSync('test/_tmp/input/shared.js', 'export const value = 42;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - const [newDynamicName, newStaticName, newChunkName] = sander - .readdirSync('test/_tmp/output') - .sort(); - assert.notEqual(newStaticName, staticName); - assert.notEqual(newDynamicName, dynamicName); - assert.notEqual(newChunkName, chunkName); - } - ]); + return copy('test/watch/samples/hashing', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: ['test/_tmp/input/main-static.js', 'test/_tmp/input/main-dynamic.js'], + output: { + dir: 'test/_tmp/output', + format: 'cjs', + exports: 'auto', + entryFileNames: '[name].[hash].js', + chunkFileNames: '[name].[hash].js' + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + [dynamicName, staticName, chunkName] = readdirSync('test/_tmp/output').sort(); + removeSync('test/_tmp/output'); + + // this should only update the hash of that particular entry point + atomicWriteFileSync( + 'test/_tmp/input/main-static.js', + "import {value} from './shared';\nexport default 2 * value;" + ); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + const [newDynamicName, newStaticName, newChunkName] = + readdirSync('test/_tmp/output').sort(); + removeSync('test/_tmp/output'); + assert.notEqual(newStaticName, staticName); + assert.strictEqual(newDynamicName, dynamicName); + assert.strictEqual(newChunkName, chunkName); + staticName = newStaticName; + + // this should update all hashes + atomicWriteFileSync('test/_tmp/input/shared.js', 'export const value = 42;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + const [newDynamicName, newStaticName, newChunkName] = + readdirSync('test/_tmp/output').sort(); + assert.notEqual(newStaticName, staticName); + assert.notEqual(newDynamicName, dynamicName); + assert.notEqual(newChunkName, chunkName); + } + ]); + }); }); it('runs transforms again on previously erroring files that were changed back', () => { const brokenFiles = new Set(); const INITIAL_CONTENT = 'export default 42;'; - sander.writeFileSync('test/_tmp/input/main.js', INITIAL_CONTENT); - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - transform(code, id) { - if (code.includes('broken')) { - brokenFiles.add(id); - throw new Error('Broken in transform'); - } else { - brokenFiles.delete(id); + promises.writeFile('test/_tmp/input/main.js', INITIAL_CONTENT).then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + transform(code, id) { + if (code.includes('broken')) { + brokenFiles.add(id); + throw new Error('Broken in transform'); + } else { + brokenFiles.delete(id); + } + }, + generateBundle() { + if (brokenFiles.size > 0) { + throw new Error('Broken in generate'); + } } }, - generateBundle() { - if (brokenFiles.size > 0) { - throw new Error('Broken in generate'); - } + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' } - }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + atomicWriteFileSync('test/_tmp/input/main.js', 'export default "broken";'); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + atomicWriteFileSync('test/_tmp/input/main.js', INITIAL_CONTENT); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + } + ]); }); - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - atomicWriteFileSync('test/_tmp/input/main.js', 'export default "broken";'); - }, - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - atomicWriteFileSync('test/_tmp/input/main.js', INITIAL_CONTENT); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - } - ]); }); it('skips filesystem writes when configured', () => { let watchChangeCnt = 0; - return sander - .copydir('test/watch/samples/skip-writes') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - watch: { - skipWrite: true - }, - plugins: { - watchChange(id) { - watchChangeCnt++; - assert.strictEqual(id, path.resolve('test/_tmp/input/main.js')); - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - watchChangeCnt = 0; - assert.strictEqual(sander.existsSync('../_tmp/output/bundle.js'), false); - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(sander.existsSync('../_tmp/output/bundle.js'), false); - assert.strictEqual(watchChangeCnt, 1); - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(sander.existsSync('../_tmp/output/bundle.js'), false); - assert.strictEqual(watchChangeCnt, 2); - atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - // 'END', - evt => { - assert.strictEqual(sander.existsSync('../_tmp/output/bundle.js'), false); - assert.strictEqual(watchChangeCnt, 3); - // still aware of its output destination - assert.strictEqual(evt.output[0], path.resolve('test/_tmp/output/bundle.js')); + return copy('test/watch/samples/skip-writes', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + watch: { + skipWrite: true + }, + plugins: { + watchChange(id) { + watchChangeCnt++; + assert.strictEqual(id, resolve('test/_tmp/input/main.js')); } - ]); + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + watchChangeCnt = 0; + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + assert.strictEqual(watchChangeCnt, 1); + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + assert.strictEqual(watchChangeCnt, 2); + atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + // 'END', + evt => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + assert.strictEqual(watchChangeCnt, 3); + // still aware of its output destination + assert.strictEqual(evt.output[0], resolve('test/_tmp/output/bundle.js')); + } + ]); + }); }); it('rebuilds immediately by default', async () => { - await sander.copydir('test/watch/samples/basic').to('test/_tmp/input'); + await copy('test/watch/samples/basic', 'test/_tmp/input'); + await wait(100); watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { @@ -1337,7 +1274,7 @@ describe('rollup.watch', () => { () => { assert.strictEqual(run('../_tmp/output/bundle.js'), 42); atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - startTime = process.hrtime(); + startTime = hrtime(); }, 'START', 'BUNDLE_START', @@ -1354,7 +1291,7 @@ describe('rollup.watch', () => { }); it('observes configured build delays', async () => { - await sander.copydir('test/watch/samples/basic').to('test/_tmp/input'); + await copy('test/watch/samples/basic', 'test/_tmp/input'); watcher = rollup.watch( [ { @@ -1411,7 +1348,7 @@ describe('rollup.watch', () => { () => { assert.strictEqual(run('../_tmp/output/bundle.js'), 42); atomicWriteFileSync('test/_tmp/input/main.js', 'export default 43;'); - startTime = process.hrtime(); + startTime = hrtime(); }, 'START', 'BUNDLE_START', @@ -1434,362 +1371,336 @@ describe('rollup.watch', () => { describe('addWatchFile', () => { it('supports adding additional watch files in plugin hooks', () => { const watchChangeIds = new Set(); - const buildStartFile = path.resolve('test/_tmp/input/buildStart'); - const loadFile = path.resolve('test/_tmp/input/load'); - const resolveIdFile = path.resolve('test/_tmp/input/resolveId'); - const transformFile = path.resolve('test/_tmp/input/transform'); + const buildStartFile = resolve('test/_tmp/input/buildStart'); + const loadFile = resolve('test/_tmp/input/load'); + const resolveIdFile = resolve('test/_tmp/input/resolveId'); + const transformFile = resolve('test/_tmp/input/transform'); const watchFiles = [buildStartFile, loadFile, resolveIdFile, transformFile]; - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - for (const file of watchFiles) sander.writeFileSync(file, 'initial'); - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + for (const file of watchFiles) writeFileSync(file, 'initial'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + buildStart() { + this.addWatchFile(buildStartFile); }, - plugins: { - buildStart() { - this.addWatchFile(buildStartFile); - }, - load() { - this.addWatchFile(loadFile); - }, - resolveId() { - this.addWatchFile(resolveIdFile); - }, - transform() { - this.addWatchFile(transformFile); - }, - watchChange(id) { - watchChangeIds.add(id); - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - // sometimes the watcher is triggered during the initial run - watchChangeIds.clear(); - for (const file of watchFiles) sander.writeFileSync(file, 'changed'); + load() { + this.addWatchFile(loadFile); }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - assert.deepStrictEqual([...watchChangeIds].sort(), watchFiles.sort()); + resolveId() { + this.addWatchFile(resolveIdFile); + }, + transform() { + this.addWatchFile(transformFile); + }, + watchChange(id) { + watchChangeIds.add(id); } - ]); + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + // sometimes the watcher is triggered during the initial run + watchChangeIds.clear(); + for (const file of watchFiles) writeFileSync(file, 'changed'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + assert.deepStrictEqual([...watchChangeIds].sort(), watchFiles.sort()); + } + ]); + }); }); it('respects changed watched files in the load hook', () => { - const WATCHED_ID = path.resolve('test/_tmp/input/watched'); - return sander - .copydir('test/watch/samples/watch-files') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - load() { - this.addWatchFile(WATCHED_ID); - return `export default "${sander.readFileSync(WATCHED_ID).toString().trim()}"`; - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 'initial'); - atomicWriteFileSync(WATCHED_ID, 'next'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 'next'); + const WATCHED_ID = resolve('test/_tmp/input/watched'); + return copy('test/watch/samples/watch-files', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + load() { + this.addWatchFile(WATCHED_ID); + return `export default "${readFileSync(WATCHED_ID).toString().trim()}"`; } - ]); + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 'initial'); + atomicWriteFileSync(WATCHED_ID, 'next'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 'next'); + } + ]); + }); }); it('respects changed watched files in the transform hook and removes them if they are no longer watched', () => { - const WATCHED_ID = path.resolve('test/_tmp/input/watched'); + const WATCHED_ID = resolve('test/_tmp/input/watched'); let addWatchFile = true; - return sander - .copydir('test/watch/samples/watch-files') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' + return copy('test/watch/samples/watch-files', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + resolveId(id) { + if (id === 'dep') { + return id; + } }, - plugins: { - resolveId(id) { - if (id === 'dep') { - return id; - } - }, - load(id) { - if (id === 'dep') { - return `throw new Error('This should not be executed);`; - } - }, - transform(code, id) { - if (id.endsWith('main.js')) { - return `export { value as default } from 'dep';`; - } else { - if (addWatchFile) { - this.addWatchFile(WATCHED_ID); - } - return `export const value = "${sander - .readFileSync(WATCHED_ID) - .toString() - .trim()}"`; - } + load(id) { + if (id === 'dep') { + return `throw new Error('This should not be executed);`; } - } - }); - const events = []; - watcher.on('event', event => events.push(event.code)); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 'initial'); - addWatchFile = false; - atomicWriteFileSync(WATCHED_ID, 'next'); }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 'next'); - atomicWriteFileSync(WATCHED_ID, 'other'); - events.length = 0; - return wait(400).then(() => assert.deepStrictEqual(events, [])); + transform(code, id) { + if (id.endsWith('main.js')) { + return `export { value as default } from 'dep';`; + } else { + if (addWatchFile) { + this.addWatchFile(WATCHED_ID); + } + return `export const value = "${readFileSync(WATCHED_ID).toString().trim()}"`; + } } - ]); + } }); + const events = []; + watcher.on('event', event => events.push(event.code)); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 'initial'); + addWatchFile = false; + atomicWriteFileSync(WATCHED_ID, 'next'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 'next'); + atomicWriteFileSync(WATCHED_ID, 'other'); + events.length = 0; + return wait(400).then(() => assert.deepStrictEqual(events, [])); + } + ]); + }); }); it('respects changed watched modules that are already part of the graph in the transform hook', () => { - return sander - .copydir('test/watch/samples/dependencies') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - transform(code, id) { - if (id.endsWith('dep1.js')) { - this.addWatchFile(path.resolve('test/_tmp/input/dep2.js')); - const text = sander.readFileSync('test/_tmp/input/dep2.js').toString().trim(); - return `export default ${JSON.stringify(text)}`; - } + return copy('test/watch/samples/dependencies', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + transform(code, id) { + if (id.endsWith('dep1.js')) { + this.addWatchFile(resolve('test/_tmp/input/dep2.js')); + const text = readFileSync('test/_tmp/input/dep2.js').toString().trim(); + return `export default ${JSON.stringify(text)}`; } } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual( - run('../_tmp/output/bundle.js'), - `dep1: "export default 'dep2';", dep2: "dep2"` - ); - atomicWriteFileSync('test/_tmp/input/dep2.js', 'export default "next";'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual( - run('../_tmp/output/bundle.js'), - `dep1: "export default "next";", dep2: "next"` - ); - } - ]); + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual( + run('../_tmp/output/bundle.js'), + `dep1: "export default 'dep2';", dep2: "dep2"` + ); + atomicWriteFileSync('test/_tmp/input/dep2.js', 'export default "next";'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual( + run('../_tmp/output/bundle.js'), + `dep1: "export default "next";", dep2: "next"` + ); + } + ]); + }); }); it('respects changed watched directories in the transform hook', () => { - const WATCHED_ID = path.resolve('test/_tmp/input/watched'); - return sander - .copydir('test/watch/samples/watch-files') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - transform() { - this.addWatchFile('test/_tmp/input'); - return `export default ${sander.existsSync(WATCHED_ID)}`; - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), true); - sander.unlinkSync(WATCHED_ID); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), false); - watcher.close(); + const WATCHED_ID = resolve('test/_tmp/input/watched'); + return copy('test/watch/samples/watch-files', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + transform() { + this.addWatchFile('test/_tmp/input'); + return `export default ${existsSync(WATCHED_ID)}`; } - ]); + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), true); + unlinkSync(WATCHED_ID); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), false); + watcher.close(); + } + ]); + }); }); it('respects initially missing added watched files', () => { - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - transform() { - this.addWatchFile('test/_tmp/input/dep'); - return `export default ${sander.existsSync('test/_tmp/input/dep')}`; - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), false); - atomicWriteFileSync('test/_tmp/input/dep', ''); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), true); + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + transform() { + this.addWatchFile('test/_tmp/input/dep'); + return `export default ${existsSync('test/_tmp/input/dep')}`; } - ]); + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), false); + atomicWriteFileSync('test/_tmp/input/dep', ''); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), true); + } + ]); + }); }); it('respects unlinked and re-added watched files', () => { - return sander - .copydir('test/watch/samples/basic') - .to('test/_tmp/input') - .then(() => { - sander.writeFileSync('test/_tmp/input/dep', ''); - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - transform() { - this.addWatchFile('test/_tmp/input/dep'); - return `export default ${sander.existsSync('test/_tmp/input/dep')}`; - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), true); - sander.unlinkSync('test/_tmp/input/dep'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), false); - atomicWriteFileSync('test/_tmp/input/dep', ''); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), true); + return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { + writeFileSync('test/_tmp/input/dep', ''); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + transform() { + this.addWatchFile('test/_tmp/input/dep'); + return `export default ${existsSync('test/_tmp/input/dep')}`; } - ]); + } }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), true); + unlinkSync('test/_tmp/input/dep'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), false); + atomicWriteFileSync('test/_tmp/input/dep', ''); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), true); + } + ]); + }); }); it('does not rerun the transform hook if a non-watched change triggered the re-run', () => { - const WATCHED_ID = path.resolve('test/_tmp/input/watched'); + const WATCHED_ID = resolve('test/_tmp/input/watched'); let transformRuns = 0; - return sander - .copydir('test/watch/samples/watch-files') - .to('test/_tmp/input') + return copy('test/watch/samples/watch-files', 'test/_tmp/input') .then(() => wait(100)) .then(() => { - sander.writeFileSync('test/_tmp/input/alsoWatched', 'initial'); + writeFileSync('test/_tmp/input/alsoWatched', 'initial'); watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { @@ -1804,7 +1715,7 @@ describe('rollup.watch', () => { transform() { transformRuns++; this.addWatchFile(WATCHED_ID); - return `export default "${sander.readFileSync(WATCHED_ID).toString().trim()}"`; + return `export default "${readFileSync(WATCHED_ID).toString().trim()}"`; } } });