-
Notifications
You must be signed in to change notification settings - Fork 99
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
Implement fast incremental compiler #85
Changes from 30 commits
62a81de
63d5e1e
e43d55b
b8248d9
0362674
1db94d5
0955fc3
18774d7
39a53d3
3da13f9
64484df
2a2952b
5acf76c
069f3e5
87f5054
9f7da6b
9c64109
b03e1c8
8339612
53012fc
f4316dd
2feb95a
1327866
d5147d2
59ab4fd
8c42b49
624b70c
77f13e5
3f722d9
da18bba
54edcdc
8fad31c
0e4b8b5
fe5035e
a666892
0b4b4fe
59e2c77
ea8a494
b70d390
bdde2e9
0cb4e0b
5476b65
71ac9d0
365214d
6f6c5d3
e96c0ca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ language: node_js | |
node_js: | ||
- "6" | ||
|
||
sudo: false | ||
sudo: required | ||
dist: trusty | ||
|
||
addons: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/* eslint-env node */ | ||
|
||
const { existsSync } = require('fs'); | ||
const path = require('path'); | ||
|
||
module.exports = { | ||
|
@@ -37,6 +38,22 @@ module.exports = { | |
}, | ||
|
||
afterInstall() { | ||
if (existsSync('.gitignore')) { | ||
this.insertIntoFile('.gitignore', '\n# Ember CLI TypeScript\n.e-c-ts'); | ||
} | ||
|
||
if (existsSync('.vscode/settings.json')) { | ||
// NOTE: this may or may not actually work -- it assumes that | ||
// `"tmp:": true` is in fact set. | ||
this.insertIntoFile('.vscode/settings.json', '",\n.e-c-ts": true', { | ||
after: '"tmp": true', | ||
}); | ||
} | ||
|
||
// TODO: same for Atom | ||
// TODO: same for Sublime | ||
// TODO: same for IntelliJ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this whole There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would think so. And if we can piggy-back off of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We rely on watchman (or other watcher, but I've only tested with watchman) to pick up the compiled js. Watchman is set up to monitor the root directory of the app, minus the excluded directories in the default {
"ignore_dirs": ["tmp", "dist"]
}
So we can't put the files in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's possible we could add another watched directory somehow but I haven't explored the APIs for it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My understanding is it would end up adding that directory as a watchman root, but I'm pretty unfamiliar with the details there, so grain of salt. Best bet is probably just to try it and see what happens ¯\_(ツ)_/¯ |
||
|
||
return this.addPackagesToProject([ | ||
{ name: 'typescript', target: 'latest' }, | ||
{ name: '@types/ember', target: 'latest' }, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// @ts-check | ||
/* eslint-env node */ | ||
|
||
const child_process = require('child_process'); | ||
const fs = require('fs'); | ||
|
||
const rimraf = require('rimraf'); | ||
const OUT_DIR = '.e-c-ts'; | ||
|
||
module.exports = (project) => { | ||
const Serve = project.require('ember-cli/lib/commands/serve'); | ||
const Builder = project.require('ember-cli/lib/models/builder'); | ||
const Watcher = project.require('ember-cli/lib/models/watcher'); | ||
|
||
/** | ||
* Exclude .ts files from being watched | ||
*/ | ||
function filterTS(name) { | ||
if (name.startsWith('.')) { | ||
// these files are filtered by default | ||
return false; | ||
} | ||
|
||
// typescript sources are watched by `tsc --watch` instead | ||
return !name.endsWith('.ts'); | ||
} | ||
|
||
class WatcherNonTS extends Watcher { | ||
buildOptions() { | ||
let options = super.buildOptions(); | ||
options.filter = filterTS; | ||
return options; | ||
} | ||
} | ||
|
||
return Serve.extend({ | ||
name: 'serve-ts', | ||
aliases: ['st'], | ||
works: 'insideProject', | ||
description: | ||
'Serve the app/addon with the TypeScript compiler in incremental mode. (Much faster!)', | ||
|
||
run(options) { | ||
this.project._isRunningServeTS = true; | ||
|
||
const builder = new Builder({ | ||
ui: this.ui, | ||
outputPath: options.outputPath, | ||
project: this.project, | ||
environment: options.environment, | ||
}); | ||
|
||
// We're ignoring this because TS doesn't have types for `Watcher`; this is | ||
// fine, though. | ||
// @ts-ignore | ||
const watcher = new WatcherNonTS({ | ||
ui: this.ui, | ||
builder, | ||
analytics: this.analytics, | ||
options, | ||
serving: true, | ||
}); | ||
|
||
options._builder = builder; | ||
options._watcher = watcher; | ||
|
||
// TODO: typescript might be installed globally? | ||
// argument sequence here is meaningful; don't apply prettier. | ||
// prettier-ignore | ||
this.tsc = child_process.fork( | ||
'node_modules/typescript/bin/tsc', | ||
[ | ||
'--watch', | ||
'--outDir', OUT_DIR, | ||
'--allowJs', 'false', | ||
'--noEmit', 'false', | ||
'--sourceMap', 'false', // TODO: enable if sourcemaps=true | ||
], | ||
{ | ||
silent: true, | ||
execArgv: [], | ||
} | ||
); | ||
this.tsc.stdout.on('data', data => { | ||
this.ui.write(data); | ||
}); | ||
this.tsc.stderr.on('data', data => { | ||
this.ui.writeError(data); | ||
}); | ||
|
||
return Serve.prototype.run.call(this, options); | ||
}, | ||
|
||
onInterrupt() { | ||
if (this.tsc) { | ||
this.tsc.kill(); | ||
} | ||
|
||
if (fs.existsSync(OUT_DIR)) { | ||
rimraf.sync(OUT_DIR); | ||
} | ||
}, | ||
}); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue described here and here on Travis' end.