Skip to content
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
9 changes: 3 additions & 6 deletions blueprints/ember-cli-typescript/files/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,8 @@ inRepoAddons.forEach(function(path) { %>,
]
}
},
"exclude": [
"tmp",
"dist",
"node_modules",
"bower_components",
"blueprints"
"include": [
"app",
"tests"
]
}
16 changes: 0 additions & 16 deletions blueprints/ember-cli-typescript/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,6 @@ 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

return this.addPackagesToProject([
{ name: 'typescript', target: 'latest' },
{ name: '@types/ember', target: 'latest' },
Expand Down
19 changes: 15 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/* eslint-env node */

const fs = require('fs');
const os = require('os');
const path = require('path');
const SilentError = require('silent-error');
const TsPreprocessor = require('./lib/typescript-preprocessor');
Expand All @@ -17,6 +18,16 @@ module.exports = {
return this.project._isRunningServeTS;
},

_tempDir() {
if (!this.project._tsTempDir) {
const tempDir = path.join(os.tmpdir(), `e-c-ts-${process.pid}`);
this.project._tsTempDir = tempDir;
mkdirp.sync(tempDir);
}

return this.project._tsTempDir;
},

_inRepoAddons() {
const pkg = this.project.pkg;
if (!pkg || !pkg['ember-addon'] || !pkg['ember-addon'].paths) {
Expand All @@ -28,7 +39,7 @@ module.exports = {

includedCommands() {
return {
'serve-ts': buildServeCommand(this.project),
'serve-ts': buildServeCommand(this.project, this._tempDir()),
};
},

Expand Down Expand Up @@ -75,10 +86,10 @@ module.exports = {

// funnel will fail if the directory doesn't exist
roots.forEach(root => {
mkdirp.sync(path.join('.e-c-ts', root));
mkdirp.sync(path.join(this._tempDir(), root));
});

const ts = funnel('.e-c-ts', {
const ts = funnel(this._tempDir(), {
exclude: ['tests'],
getDestinationPath(relativePath) {
const prefix = roots.find(root => relativePath.startsWith(root));
Expand All @@ -99,7 +110,7 @@ module.exports = {
return tree;
}

const tests = path.join('.e-c-ts', 'tests');
const tests = path.join(this._tempDir(), 'tests');

// funnel will fail if the directory doesn't exist
mkdirp.sync(tests);
Expand Down
124 changes: 73 additions & 51 deletions lib/serve-ts.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ const child_process = require('child_process');
const fs = require('fs');

const rimraf = require('rimraf');
const OUT_DIR = '.e-c-ts';

module.exports = (project) => {
module.exports = (project, outDir) => {
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');
Expand Down Expand Up @@ -41,64 +40,87 @@ module.exports = (project) => {
'Serve the app/addon with the TypeScript compiler in incremental mode. (Much faster!)',

run(options) {
const config = this.project.config(options.environment);

this.project._isRunningServeTS = true;

const builder = new Builder({
ui: this.ui,
outputPath: options.outputPath,
project: this.project,
environment: options.environment,
});
return new Promise(resolve => {
let started = false;

// 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,
});
this.ui.startProgress('Starting TypeScript compilation...');

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);
});
// 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', outDir,
'--allowJs', 'false',
'--noEmit', 'false',
'--sourceMap', 'false', // TODO: enable if sourcemaps=true
],
{
silent: true,
execArgv: [],
}
);

this.tsc.stderr.on('data', data => {
this.ui.writeError(data);
});

this.tsc.stdout.on('data', data => {
this.ui.write(data);

return Serve.prototype.run.call(this, options);
// Wait for the initial compilation to complete before continuing to
// minimize thrashing during startup.
if (data.indexOf('Compilation complete') !== -1 && !started) {
started = true;
this.ui.stopProgress();
resolve();
}
});
}).then(() => {
const builder = new Builder({
ui: this.ui,
outputPath: options.outputPath,
project: this.project,
environment: options.environment,
});

// This will be populated later by the superclass, but is needed by the Watcher now
options.rootURL = config.rootURL || '/';

// 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;

return Serve.prototype.run.call(this, options);
});
},

onInterrupt() {
if (this.tsc) {
this.tsc.kill();
}
return Serve.prototype.onInterrupt.apply(this, arguments).then(() => {
if (this.tsc) {
this.tsc.kill();
}

if (fs.existsSync(OUT_DIR)) {
rimraf.sync(OUT_DIR);
}
if (fs.existsSync(outDir)) {
rimraf.sync(outDir);
}
});
},
});
};