8000 #2 add watch patterns by catdad · Pull Request #48 · catdad/electronmon · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

#2 add watch patterns #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ That's it! Now, all your files are watched. Changes to main process files will c

All you have to do now is write your application code.

## Configuration

Okay, okay... so it's not exactly magic. While `electronmon` will usually work exactly the way you want it to, you might find a need to contigure it. You can do so by providing extra values in your `package.json` in the an `electronmon` object. The following options are available:

* **`patterns`** _`{Array<String>}`_ - Additional patterns to watch, in glob form. The default patterns are `['**/*', '!node_modules', '!node_modules/**/*', '!.*', '!**/*.map']`, and this property will add to that. If you want to ignore some files, start the glob with `!`.

**Example:**

```json
{
"electronmon": {
"patterns": ["!test/**"]
}
}
```

## Supported environments

This module is tested and supported on Windows, MacOS, and Linux, using node versions 8, 10, and 12 and electron versions 3, 4, 5, 6, 7, and 8.
Expand All @@ -51,11 +67,12 @@ const electronmon = require('electronmon');

All options are optional with reasonable defaults (_again, magic_ 🧙), but the following options are available:

* **`cwd`** _{String}_ - The root directory of your application
* **`args`** _{Array}_ - The arguments that you want to pass to `electron`
* **`env`** _{Object}_ - Any additional environment variables you would like to specically provide to your `electron` process
* **`logLevel`** _{String}_ - The level of logging you would like. Possible values are `verbose`, `info`, ` error`, and `quiet`
* **`electronPath`** _{String}_ - The path to the `electron` binary.
* **`cwd`** _`{String}`_ - The root directory of your application.
* **`args`** _`{Array<String>}`_ - The arguments that you want to pass to `electron`.
* **`env`** _`{Object}`_ - Any additional environment variables you would like to specically provide to your `electron` process.
* **`patterns`** _`{Array<String>}`_ - Additional patterns to watch, in glob form. The default patterns are `['**/*', '!node_modules', '!node_modules/**/*', '!.*', '!**/*.map']`, and this property will add to that. If you want to ignore some files, start the glob with `!`.
* **`logLevel`** _`{String}`_ - The level of logging you would like. Possible values are `verbose`, `info`, ` error`, and `quiet`.
* **`electronPath`** _`{String}`_ - The path to the `electron` binary.

When the monitor is started, it will start your application and the monitoring process. It exposes the following methods for interacting with the monitoring process (all methods are asynchronous and return a Promise):

Expand Down
3 changes: 2 additions & 1 deletion bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ const pkg = require('../src/package.js');
const cwd = fs.realpathSync(path.resolve('.'));
const args = process.argv.slice(2);
const logLevel = process.env.ELECTRONMON_LOGLEVEL || 'info';
const patterns = Array.isArray(pkg.electronmon.patterns) ? pkg.electronmon.patterns : [];

if (pkg.name) {
process.title = `${pkg.name} - electronmon`;
} else {
process.title = 'electronmon';
}

require('../')({ cwd, args, logLevel, electronPath });
require('../')({ cwd, args, logLevel, electronPath, patterns });
1 change: 1 addition & 0 deletions package.json
10000
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"chai": "^4.2.0",
"electron": "^4.0.8",
"eslint": "^5.16.0",
"fs-extra": "^8.1.0",
"mocha": "^6.2.2",
"node-stream": "^1.7.0",
"symlink-dir": "^3.1.1",
Expand Down
5 changes: 3 additions & 2 deletions src/electronmon.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ module.exports = ({
env = {},
logLevel = 'info',
electronPath,
stdio = [process.stdin, process.stdout, process.stderr]
stdio = [process.stdin, process.stdout, process.stderr],
patterns = []
} = {}) => {
const executable = electronPath || require('electron');

Expand Down Expand Up @@ -150,7 +151,7 @@ module.exports = ({

function startWatcher() {
return new Promise((resolve) => {
const watcher = watch({ root: cwd });
const watcher = watch({ root: cwd, patterns });
globalWatcher = watcher;

watcher.on('change', ({ path: fullpath }) => {
Expand Down
12 changes: 11 additions & 1 deletion src/package.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
const fs = require('fs');

module.exports = (() => {
const read = () => {
try {
const packageText = fs.readFileSync('./package.json', 'utf8');
return JSON.parse(packageText || '{}');
} catch (e) {
return {};
}
};

module.exports = (() => {
const pkg = read();

pkg.electronmon = Object.assign({
patterns: []
}, pkg.electronmon);

return pkg;
})();
6 changes: 4 additions & 2 deletions src/watch.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const watchboy = require('watchboy');

module.exports = ({ root }) => {
const watcher = watchboy(['**/*', '!node_modules', '!node_modules/**/*', '!.*', '!**/*.map'], {
const PATTERNS = ['**/*', '!node_modules', '!node_modules/**/*', '!.*', '!**/*.map'];

module.exports = ({ root, patterns }) => {
const watcher = watchboy([...PATTERNS, ...patterns.map(s => `${s}`)], {
cwd: root
});

Expand Down
113 changes: 92 additions & 21 deletions test/integration.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const path = require('path');
const fs = require('fs');
const fs = require('fs-extra');
const { PassThrough } = require('stream');
const { spawn } = require('child_process');
const ns = require('node-stream');
Expand Down Expand Up @@ -65,20 +65,26 @@ describe('integration', () => {
});
};

const ready = stream => {
const ready = (stream, { main = true, renderer = true, index = true } = {}) => {
return Promise.all([
waitFor(stream, /main window open/),
waitFor(stream, /watching new file: main\.js/),
waitFor(stream, /watching new file: renderer\.js/),
waitFor(stream, /watching new file: index\.html/)
main ? waitFor(stream, /watching new file: main\.js/) : Promise.resolve(),
renderer ? waitFor(stream, /watching new file: renderer\.js/) : Promise.resolve(),
index ? waitFor(stream, /watching new file: index\.html/) : Promise.resolve()
]);
};

function runIntegrationTests(realRoot, cwd, start) {
const file = fixturename => {
return path.resolve(realRoot, fixturename);
};
const createCopy = async () => {
const root = path.resolve(__dirname, '../fixtures');
const copyDir = path.resolve(__dirname, '..', `test-dir-${Math.random().toString(36).slice(2)}`);

await fs.ensureDir(copyDir);
await fs.copy(root, copyDir);

return copyDir;
};

function runIntegrationTests(realRoot, cwd, start, file) {
it('watches files for restarts or refreshes', async () => {
const app = await start({
args: ['main.js'],
Expand Down Expand Up @@ -174,28 +180,85 @@ describe('integration', () => {
}

function runIntegrationSuite(start) {
const root = path.resolve(__dirname, '../fixtures');

const file = fixturename => {
return path.resolve(root, fixturename);
};

describe('when running the app from project directory', () => {
const root = path.resolve(__dirname, '../fixtures');
runIntegrationTests(root, root, start);
runIntegrationTests(root, root, start, file);
});

describe('when running the app from a linked directory', () => {
const root = path.resolve(__dirname, '../fixtures');
const linkDir = path.resolve(__dirname, '..', `test-dir-${Math.random().toString(36).slice(2)}`);

before(async () => {
await symlink(root, linkDir);
});
after((done) => {
fs.unlink(linkDir, done);
after(async () => {
await fs.unlink(linkDir);
});

it(`making sure link exists at ${linkDir}`, () => {
const realPath = fs.realpathSync(linkDir);
it(`making sure link exists at ${linkDir}`, async () => {
const realPath = await fs.realpath(linkDir);
expect(realPath).to.equal(root);
});

runIntegrationTests(root, linkDir, start);
runIntegrationTests(root, linkDir, start, file);
});

describe('when providing watch patterns', () => {
let dir;

const fileLocal = fixturename => {
return path.resolve(dir, fixturename);
};

beforeEach(async () => {
dir = await createCopy();
});
afterEach(async () => {
fs.remove(dir);
});

it('ignores files defined by negative patterns', async () => {
const app = await start({
args: ['main.js'],
cwd: dir,
env: Object.assign({}, process.env, {
ELECTRONMON_LOGLEVEL: 'verbose'
}),
patterns: ['!main-error.js', '!*.html']
});

const stdout = collect(wrap(app.stdout));

await ready(stdout, { index: false });

await Promise.all([
waitFor(stdout, /renderer file change: renderer\.js/),
touch(fileLocal('renderer.js'))
]);

const linesBefore = [].concat(stdout._getLines());
await touch(fileLocal('index.html'));
const linesAfter = [].concat(stdout._getLines());

expect(linesAfter).to.deep.equal(linesBefore);

await Promise.all([
waitFor(stdout, /main file change: main\.js/),
waitFor(stdout, /restarting app due to file change/),
waitFor(stdout, /main window open/),
touch(fileLocal('main-error.js')),
touch(fileLocal('main.js'))
]);

const mainErrorChanged = stdout._getLines().find(line => !!line.match(/main file change: main-error\.js/));

expect(mainErrorChanged).to.equal(undefined);
});
});
}

Expand All @@ -221,15 +284,16 @@ describe('integration', () => {
app = null;
});

const start = async ({ args, cwd, env }) => {
const start = async ({ args, cwd, env, patterns = [] }) => {
const pass = new PassThrough();
app = await api({
// NOTE: the API should always use realPath
cwd: fs.realpathSync(cwd),
cwd: await fs.realpath(cwd),
args,
env,
stdio: [process.stdin, pass, pass],
logLevel: env.ELECTRONMON_LOGLEVEL || 'verbose'
logLevel: env.ELECTRONMON_LOGLEVEL || 'verbose',
patterns
});

app.stdout = pass;
Expand Down Expand Up @@ -321,7 +385,14 @@ describe('integration', () => {
});
});

const start = async ({ args, cwd, env }) => {
const start = async ({ args, cwd, env, patterns }) => {
if (patterns && patterns.length) {
const pkgPath = path.resolve(cwd, 'package.json');
const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
pkg.electronmon = { patterns };
await fs.writeFile(pkgPath, JSON.stringify(pkg));
}

app = spawn(process.execPath, [cli].concat(args), {
env,
cwd,
Expand Down
0