From 334ecfa2f18cc3d29b57f81a780f1c0767ccf6f2 Mon Sep 17 00:00:00 2001 From: sainthkh Date: Sat, 2 Feb 2019 09:14:58 +0900 Subject: [PATCH 1/5] Add new files to the main bundle tree. And remove them when they're removed (#667) --- packages/core/parcel-bundler/src/Bundler.js | 36 ++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/core/parcel-bundler/src/Bundler.js b/packages/core/parcel-bundler/src/Bundler.js index 98238faa5a2..df254ec46f4 100644 --- a/packages/core/parcel-bundler/src/Bundler.js +++ b/packages/core/parcel-bundler/src/Bundler.js @@ -19,7 +19,7 @@ const installPackage = require('./utils/installPackage'); const bundleReport = require('./utils/bundleReport'); const prettifyTime = require('./utils/prettifyTime'); const getRootDir = require('./utils/getRootDir'); -const {glob} = require('./utils/glob'); +const {glob, isGlob} = require('./utils/glob'); /** * The Bundler is the main entry point. It resolves and loads assets, @@ -59,6 +59,7 @@ class Bundler extends EventEmitter { this.pending = false; this.loadedAssets = new Map(); this.watchedAssets = new Map(); + this.watchedGlobs = entryFiles.filter(entry => isGlob(entry)); this.farm = null; this.watcher = null; @@ -372,7 +373,12 @@ class Bundler extends EventEmitter { if (process.env.NODE_ENV === 'test' && !this.watcher.ready) { await new Promise(resolve => this.watcher.once('ready', resolve)); } + this.watchedGlobs.forEach(glob => { + this.watcher.add(glob); + }); + this.watcher.on('add', this.onAdd.bind(this)); this.watcher.on('change', this.onChange.bind(this)); + this.watcher.on('unlink', this.onUnlink.bind(this)); } if (this.options.hmr) { @@ -758,7 +764,24 @@ class Bundler extends EventEmitter { } } + async onAdd(path) { + path = Path.join(process.cwd(), path); + + let asset = this.parser.getAsset(path, this.options); + this.loadedAssets.set(path, asset); + + this.entryAssets.add(asset); + + await this.watch(path, asset); + this.onChange(path); + } + async onChange(path) { + // The path to the newly-added items are not absolute. + if (!Path.isAbsolute(path)) { + path = Path.resolve(process.cwd(), path); + } + let assets = this.watchedAssets.get(path); if (!assets || !assets.size) { return; @@ -779,6 +802,17 @@ class Bundler extends EventEmitter { }, 100); } + async onUnlink(path) { + // The path to the newly-added items are not absolute. + if (!Path.isAbsolute(path)) { + path = Path.resolve(process.cwd(), path); + } + + let asset = this.getLoadedAsset(path); + this.entryAssets.delete(asset); + this.unloadAsset(asset); + } + middleware() { this.bundle(); return Server.middleware(this); From 0fb7c8bc27f39d4f91a7449fa1a75556d47d617f Mon Sep 17 00:00:00 2001 From: sainthkh Date: Sat, 2 Feb 2019 10:07:16 +0900 Subject: [PATCH 2/5] Fixed the failing tests because entryFiles can be null. --- packages/core/parcel-bundler/src/Bundler.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/core/parcel-bundler/src/Bundler.js b/packages/core/parcel-bundler/src/Bundler.js index df254ec46f4..9acbd0b5b38 100644 --- a/packages/core/parcel-bundler/src/Bundler.js +++ b/packages/core/parcel-bundler/src/Bundler.js @@ -29,7 +29,9 @@ class Bundler extends EventEmitter { constructor(entryFiles, options = {}) { super(); - this.entryFiles = this.normalizeEntries(entryFiles); + entryFiles = this.normalizeEntries(entryFiles); + this.watchedGlobs = entryFiles.filter(entry => isGlob(entry)); + this.entryFiles = this.findEntryFiles(entryFiles); this.options = this.normalizeOptions(options); this.resolver = new Resolver(this.options); @@ -59,7 +61,6 @@ class Bundler extends EventEmitter { this.pending = false; this.loadedAssets = new Map(); this.watchedAssets = new Map(); - this.watchedGlobs = entryFiles.filter(entry => isGlob(entry)); this.farm = null; this.watcher = null; @@ -83,6 +84,10 @@ class Bundler extends EventEmitter { entryFiles = [process.cwd()]; } + return entryFiles; + } + + findEntryFiles(entryFiles) { // Match files as globs return entryFiles .reduce((p, m) => p.concat(glob.sync(m)), []) From c2cbd437dd2928b427012a1af5a274e91223718a Mon Sep 17 00:00:00 2001 From: sainthkh Date: Sat, 2 Feb 2019 13:18:02 +0900 Subject: [PATCH 3/5] Added tests for detecting dir changes and rebuilds. --- packages/core/parcel-bundler/src/Bundler.js | 2 + .../parcel-bundler/test/detect-dir-change.js | 131 ++++++++++++++++++ .../detect-dir-change/src/index.js | 3 + 3 files changed, 136 insertions(+) create mode 100644 packages/core/parcel-bundler/test/detect-dir-change.js create mode 100644 packages/core/parcel-bundler/test/integration/detect-dir-change/src/index.js diff --git a/packages/core/parcel-bundler/src/Bundler.js b/packages/core/parcel-bundler/src/Bundler.js index 9acbd0b5b38..f30ae772a52 100644 --- a/packages/core/parcel-bundler/src/Bundler.js +++ b/packages/core/parcel-bundler/src/Bundler.js @@ -816,6 +816,8 @@ class Bundler extends EventEmitter { let asset = this.getLoadedAsset(path); this.entryAssets.delete(asset); this.unloadAsset(asset); + + this.bundle(); } middleware() { diff --git a/packages/core/parcel-bundler/test/detect-dir-change.js b/packages/core/parcel-bundler/test/detect-dir-change.js new file mode 100644 index 00000000000..439c053b1cf --- /dev/null +++ b/packages/core/parcel-bundler/test/detect-dir-change.js @@ -0,0 +1,131 @@ +const assert = require('assert'); +const Path = require('path'); +const fs = require('@parcel/fs'); +const {rimraf, ncp, bundler, run, nextBundle} = require('./utils'); +const {sleep} = require('@parcel/test-utils'); + +let inputRoot = Path.join(__dirname, 'input', 'detect-dir-change'); + +describe('detect directory changes', function() { + beforeEach(async function() { + await rimraf(inputRoot); + await fs.mkdirp(inputRoot); + await ncp(__dirname + '/integration/detect-dir-change/', inputRoot); + }); + + describe('when a file matches a glob', async function() { + it('should rebuild when the file is added', async function() { + // 1. Bundle + let b = bundler('test/input/detect-dir-change/src/*.js', { + watch: true + }); + let bundle = await b.bundle(); + + assert(await fs.exists(Path.join(__dirname, '/dist/', 'index.js'))); + + // We'll check if bundle is called with this listener. + let bundled = false; + b.on('bundled', () => { + bundled = true; + }); + + // 2. Write file and assert. + await fs.writeFile( + Path.join(inputRoot, './src/app.js'), + "module.exports = function () { return 'app' }" + ); + + await sleep(1000); + + assert(bundled); + }); + + it('should rebuild when the file is removed', async function() { + // 1. Add file and check the result bundle has all files. + let filePath = Path.join(inputRoot, './src/app.js'); + await fs.writeFile( + filePath, + "module.exports = function () { return 'app' }" + ); + + let b = bundler('test/input/detect-dir-change/src/*.js', { + watch: true + }); + + let bundle = await b.bundle(); + + let childBundleNames = Array.from(bundle.childBundles.values()).map( + bundle => Path.basename(bundle.name) + ); + + assert(childBundleNames.includes('index.js')); + assert(childBundleNames.includes('app.js')); + + // We'll check if bundle is called with this listener. + let bundled = false; + b.on('bundled', () => { + bundled = true; + }); + + // 2. Check dist file removed correctly. + await fs.unlink(filePath); + + await sleep(1000); + assert(bundled); + }); + }); + + describe('when a file does not match a glob', async function() { + it('should not rebuild when the file is added', async function() { + // 1. Bundle + let b = bundler('test/input/detect-dir-change/src/*.js', { + watch: true + }); + let bundle = await b.bundle(); + let output = await run(bundle); + + assert(await fs.exists(Path.join(__dirname, '/dist/', 'index.js'))); + + // We'll check if bundle is called with this listener. + let bundled = false; + b.on('bundled', () => { + bundled = true; + }); + + // 2. Create unrelated file and assert + await fs.writeFile( + Path.join(inputRoot, './src/app2.ts'), + "module.exports = function () { return 'app' }" + ); + + await sleep(1000); + assert(!bundled); + }); + + it('should not rebuild when the file is removed', async function() { + // 1. Add file and check bundle has all files. + let filePath = Path.join(inputRoot, './src/test.html'); + await fs.writeFile(filePath, ''); + + let b = bundler('test/input/detect-dir-change/src/*.js', { + watch: true + }); + + let bundle = await b.bundle(); + + assert(Path.basename(bundle.name), 'index.js'); + + // We'll check if bundle is called with this listener. + let bundled = false; + b.on('bundled', () => { + bundled = true; + }); + + // 2. Remove file and assert that bundle() isn't called. + await fs.unlink(filePath); + + await sleep(1000); + assert(!bundled); + }); + }); +}); diff --git a/packages/core/parcel-bundler/test/integration/detect-dir-change/src/index.js b/packages/core/parcel-bundler/test/integration/detect-dir-change/src/index.js new file mode 100644 index 00000000000..dc1d27ea630 --- /dev/null +++ b/packages/core/parcel-bundler/test/integration/detect-dir-change/src/index.js @@ -0,0 +1,3 @@ +module.exports = function() { + return 'hello'; +} \ No newline at end of file From 15c17923783edd55913ee9f5b2b68252db1047e4 Mon Sep 17 00:00:00 2001 From: sainthkh Date: Sat, 2 Feb 2019 16:34:12 +0900 Subject: [PATCH 4/5] Fixed eslint problems. --- packages/core/parcel-bundler/test/detect-dir-change.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/core/parcel-bundler/test/detect-dir-change.js b/packages/core/parcel-bundler/test/detect-dir-change.js index 439c053b1cf..ec55de68459 100644 --- a/packages/core/parcel-bundler/test/detect-dir-change.js +++ b/packages/core/parcel-bundler/test/detect-dir-change.js @@ -1,7 +1,7 @@ const assert = require('assert'); const Path = require('path'); const fs = require('@parcel/fs'); -const {rimraf, ncp, bundler, run, nextBundle} = require('./utils'); +const {rimraf, ncp, bundler} = require('./utils'); const {sleep} = require('@parcel/test-utils'); let inputRoot = Path.join(__dirname, 'input', 'detect-dir-change'); @@ -19,7 +19,7 @@ describe('detect directory changes', function() { let b = bundler('test/input/detect-dir-change/src/*.js', { watch: true }); - let bundle = await b.bundle(); + await b.bundle(); assert(await fs.exists(Path.join(__dirname, '/dist/', 'index.js'))); @@ -81,8 +81,7 @@ describe('detect directory changes', function() { let b = bundler('test/input/detect-dir-change/src/*.js', { watch: true }); - let bundle = await b.bundle(); - let output = await run(bundle); + await b.bundle(); assert(await fs.exists(Path.join(__dirname, '/dist/', 'index.js'))); From c370f3e4d23ec80a34397517da660c093f18db77 Mon Sep 17 00:00:00 2001 From: sainthkh Date: Tue, 12 Feb 2019 08:23:06 +0900 Subject: [PATCH 5/5] Fixed tests that depended on old utils.js file. --- packages/core/parcel-bundler/test/detect-dir-change.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/parcel-bundler/test/detect-dir-change.js b/packages/core/parcel-bundler/test/detect-dir-change.js index ec55de68459..7dd8d9a847f 100644 --- a/packages/core/parcel-bundler/test/detect-dir-change.js +++ b/packages/core/parcel-bundler/test/detect-dir-change.js @@ -1,8 +1,7 @@ const assert = require('assert'); const Path = require('path'); const fs = require('@parcel/fs'); -const {rimraf, ncp, bundler} = require('./utils'); -const {sleep} = require('@parcel/test-utils'); +const {sleep, rimraf, ncp, bundler} = require('@parcel/test-utils'); let inputRoot = Path.join(__dirname, 'input', 'detect-dir-change');