Skip to content
This repository has been archived by the owner on Dec 8, 2022. It is now read-only.

Commit

Permalink
Fixed skyux test/watch performance (#202)
Browse files Browse the repository at this point in the history
* Removed tslint-loader
* Created custom sky-tslint loader
  • Loading branch information
Blackbaud-SteveBrush authored Jun 29, 2017
1 parent 978813f commit 4272474
Show file tree
Hide file tree
Showing 10 changed files with 245 additions and 60 deletions.
3 changes: 2 additions & 1 deletion config/webpack/build.webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ function getWebpackConfig(skyPagesConfig) {
// Ignore the "Cannot find module" error that occurs when referencing
// an aliased file. Webpack will still throw an error when a module
// cannot be resolved via a file path or alias.
ignoreDiagnostics: [2307]
ignoreDiagnostics: [2307],
transpileOnly: true
}
},
{
Expand Down
15 changes: 5 additions & 10 deletions config/webpack/serve.webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
const skyPagesConfigUtil = require('../sky-pages/sky-pages.config');
const hostUtils = require('../../utils/host-utils');

const moduleLoader = skyPagesConfigUtil.outPath('loader', 'sky-pages-module');

/**
* Returns the querystring base for parameters allowed to be passed through.
* PLEASE NOTE: The method is nearly duplicated in `runtime/params.ts`.
Expand Down Expand Up @@ -120,11 +118,6 @@ function getWebpackConfig(argv, skyPagesConfig) {
watch: true,
module: {
rules: [
{
enforce: 'pre',
test: /sky-pages\.module\.ts$/,
loader: moduleLoader
},
{
test: /\.ts$/,
use: [
Expand All @@ -134,15 +127,17 @@ function getWebpackConfig(argv, skyPagesConfig) {
// Ignore the "Cannot find module" error that occurs when referencing
// an aliased file. Webpack will still throw an error when a module
// cannot be resolved via a file path or alias.
ignoreDiagnostics: [2307]
ignoreDiagnostics: [2307],
transpileOnly: true
}
},
{
loader: 'angular2-template-loader'
}
]
],
exclude: [/\.e2e\.ts$/]
}
],
]
},
devServer: {
compress: true,
Expand Down
80 changes: 33 additions & 47 deletions config/webpack/test.webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
/*jslint node: true */
'use strict';

function getWebpackConfig(skyPagesConfig, argv) {

function spaPath() {
return skyPagesConfigUtil.spaPath.apply(skyPagesConfigUtil, arguments);
}

function outPath() {
return skyPagesConfigUtil.outPath.apply(skyPagesConfigUtil, arguments);
}

const path = require('path');
const path = require('path');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');
const ProcessExitCode = require('../../plugin/process-exit-code');
const SkyTsLintCheckerPlugin = require('../../loader/sky-tslint/checker-plugin');
const skyPagesConfigUtil = require('../sky-pages/sky-pages.config');
const aliasBuilder = require('./alias-builder');

function spaPath() {
return skyPagesConfigUtil.spaPath.apply(skyPagesConfigUtil, arguments);
}

const DefinePlugin = require('webpack/lib/DefinePlugin');
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');
const ProcessExitCode = require('../../plugin/process-exit-code');
const skyPagesConfigUtil = require('../sky-pages/sky-pages.config');
const aliasBuilder = require('./alias-builder');
function outPath() {
return skyPagesConfigUtil.outPath.apply(skyPagesConfigUtil, arguments);
}

function getWebpackConfig(skyPagesConfig, argv) {
const runCoverage = (!argv || argv.coverage !== false);
skyPagesConfig.runtime.includeRouteModule = false;

const ENV = process.env.ENV = process.env.NODE_ENV = 'test';
const srcPath = path.resolve(process.cwd(), 'src', 'app');
const moduleLoader = outPath('loader', 'sky-pages-module');

const resolves = [
process.cwd(),
Expand Down Expand Up @@ -66,17 +64,7 @@ function getWebpackConfig(skyPagesConfig, argv) {
{
enforce: 'pre',
test: /sky-pages\.module\.ts$/,
loader: moduleLoader
},
{
enforce: 'pre',
test: /\.ts$/,
loader: 'tslint-loader',
exclude: excludes,
options: {
emitErrors: true,
failOnHint: true
}
loader: outPath('loader', 'sky-pages-module')
},
{
enforce: 'pre',
Expand All @@ -87,7 +75,13 @@ function getWebpackConfig(skyPagesConfig, argv) {
{
enforce: 'pre',
loader: outPath('loader', 'sky-processor', 'preload'),
exclude: /node_modules/
exclude: excludes
},
{
enforce: 'pre',
test: /\.ts$/,
loader: outPath('loader', 'sky-tslint'),
exclude: excludes
},
{
test: /\.ts$/,
Expand All @@ -98,7 +92,9 @@ function getWebpackConfig(skyPagesConfig, argv) {
// Ignore the "Cannot find module" error that occurs when referencing
// an aliased file. Webpack will still throw an error when a module
// cannot be resolved via a file path or alias.
ignoreDiagnostics: [2307]
ignoreDiagnostics: [2307],
// Linting is handled by the sky-tslint loader.
transpileOnly: true
}
},
{
Expand All @@ -108,19 +104,12 @@ function getWebpackConfig(skyPagesConfig, argv) {
exclude: [/\.e2e\.ts$/]
},
{
test: /\.css$/,
loader: 'raw-loader'
test: /\.s?css$/,
use: ['raw-loader', 'sass-loader']
},
{
test: /\.html$/,
loader: 'raw-loader'
},
{
test: /\.scss$/,
use: [
'raw-loader',
'sass-loader'
]
}
]
},
Expand All @@ -130,13 +119,7 @@ function getWebpackConfig(skyPagesConfig, argv) {
debug: true,
options: {
context: __dirname,
skyPagesConfig: skyPagesConfig,
tslint: {
emitErrors: false,
failOnHint: false,
resourcePath: 'src',
typeCheck: true
}
skyPagesConfig: skyPagesConfig
}
}),

Expand All @@ -159,6 +142,9 @@ function getWebpackConfig(skyPagesConfig, argv) {
{}
),

// Handles watch-mode maintenance for TSLint.
new SkyTsLintCheckerPlugin(),

// Webpack 2 behavior does not correctly return non-zero exit code.
new ProcessExitCode()
]
Expand Down
14 changes: 14 additions & 0 deletions loader/sky-tslint/checker-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*jshint node: true*/
'use strict';

module.exports = function () {
const apply = (compiler) => {
compiler.plugin('done', () => {
// Delete the existing TSLint program after each compilation so that it will get
// recreated when files change.
require('./program').clearProgram();
});
};

return { apply };
};
32 changes: 32 additions & 0 deletions loader/sky-tslint/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*jshint node: true*/
'use strict';

const tslint = require('tslint');
const skyPagesConfigUtil = require('../../config/sky-pages/sky-pages.config');
const programUtil = require('./program');
const tslintConfigPath = skyPagesConfigUtil.spaPath('tslint.json');
const tsConfigPath = skyPagesConfigUtil.spaPath('tsconfig.json');

const lint = (instance, input) => {
const linterOptions = {
fix: false,
typeCheck: true
};

const program = programUtil.getProgram(tsConfigPath);
const configuration = tslint.Configuration.findConfiguration(tslintConfigPath).results;
const linter = new tslint.Linter(linterOptions, program);
linter.lint(instance.resourcePath, input, configuration);
const result = linter.getResult();

if (result.failures.length) {
return new Error(`Compilation failed due to tslint errors. ${result.output}`);
}
};

module.exports = function (input, map) {
const callback = this.async();
const error = lint(this, input);

callback(error, input, map);
};
25 changes: 25 additions & 0 deletions loader/sky-tslint/program.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*jshint node: true*/
'use strict';

const tslint = require('tslint');
const logger = require('winston');
let _program;

const getProgram = (tsconfigPath) => {
if (!_program) {
logger.info('Creating new TSLint compiler...');
_program = tslint.Linter.createProgram(tsconfigPath);
logger.info('Done.');
}

return _program;
};

const clearProgram = () => {
_program = undefined;
};

module.exports = {
getProgram,
clearProgram
};
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"homepage": "https://github.com/blackbaud/skyux-builder#readme",
"peerDependencies": {
"@blackbaud/skyux": "2.0.0-rc.1"
"@blackbaud/skyux": "2.0.0-rc.2"
},
"dependencies": {
"@angular/common": "4.1.3",
Expand Down Expand Up @@ -86,7 +86,6 @@
"ts-helpers": "1.1.2",
"ts-node": "3.0.4",
"tslint": "5.2.0",
"tslint-loader": "3.5.3",
"typescript": "2.3.2",
"webpack": "2.5.1",
"webpack-dev-server": "2.4.5",
Expand Down
19 changes: 19 additions & 0 deletions test/loader-tslint-checker.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*jshint jasmine: true, node: true */
'use strict';

const programUtil = require('../loader/sky-tslint/program');

describe('SKY UX tslint Webpack checker plugin', () => {
const pluginPath = '../loader/sky-tslint/checker-plugin';

it('should delete the TSLint program on the "done" hook', () => {
spyOn(programUtil, 'clearProgram').and.callFake(() => {});
const plugin = require(pluginPath);
const mockCompiler = {
plugin: (hook, callback) => callback()
};
const instance = new plugin();
instance.apply(mockCompiler);
expect(programUtil.clearProgram).toHaveBeenCalled();
});
});
48 changes: 48 additions & 0 deletions test/loader-tslint-program.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*jshint jasmine: true, node: true */
'use strict';

const mock = require('mock-require');
const tslint = require('tslint');

describe('SKY UX tslint program util', () => {
const utilPath = '../loader/sky-tslint/program';

beforeEach(() => {
spyOn(tslint.Linter, 'createProgram').and.returnValue({});
});

afterEach(() => {
mock.stopAll();
});

it('should create and return a TSLint program based on tsconfig.json path', () => {
const util = mock.reRequire(utilPath);
const tsconfigPath = 'tsconfig.json';
const program = util.getProgram(tsconfigPath);
expect(program).toBeDefined();
expect(tslint.Linter.createProgram).toHaveBeenCalledWith(tsconfigPath);
});

it('should return an existing TSLint program on proceeding requests', () => {
const util = mock.reRequire(utilPath);
const tsconfigPath = 'tsconfig.json';

util.getProgram(tsconfigPath);
expect(tslint.Linter.createProgram.calls.count()).toEqual(1);

util.getProgram(tsconfigPath);
expect(tslint.Linter.createProgram.calls.count()).toEqual(1);
});

it('should delete a TSLint program', () => {
const util = mock.reRequire(utilPath);
const tsconfigPath = 'tsconfig.json';

util.getProgram(tsconfigPath);
expect(tslint.Linter.createProgram.calls.count()).toEqual(1);

util.clearProgram();
util.getProgram(tsconfigPath);
expect(tslint.Linter.createProgram.calls.count()).toEqual(2);
});
});
Loading

0 comments on commit 4272474

Please sign in to comment.