Skip to content
This repository was archived by the owner on Dec 1, 2019. It is now read-only.

Commit 7193589

Browse files
author
Stanislav Panferov
committed
feat(*): learn loader to pick-up precompiled files if any
1 parent 6e6c482 commit 7193589

File tree

4 files changed

+119
-18
lines changed

4 files changed

+119
-18
lines changed

src/deps.ts

+59
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as _ from 'lodash';
22
import * as util from 'util';
33
import * as path from 'path';
4+
import * as fs from 'fs';
45
import * as Promise from 'bluebird';
56

67
import { State } from './host';
@@ -230,10 +231,12 @@ export interface IDependencyGraphItem {
230231
export class DependencyManager {
231232
dependencies: {[fileName: string]: string[]};
232233
knownTypeDeclarations: FileSet;
234+
compiledModules: {[fileName: string]: string[]};
233235

234236
constructor(dependencies: {[fileName: string]: string[]} = {}, knownTypeDeclarations: FileSet = {}) {
235237
this.dependencies = dependencies;
236238
this.knownTypeDeclarations = knownTypeDeclarations;
239+
this.compiledModules = {};
237240
}
238241

239242
clone(): DependencyManager {
@@ -251,10 +254,26 @@ export class DependencyManager {
251254
this.dependencies[fileName].push(depFileName);
252255
}
253256

257+
addCompiledModule(fileName: string, depFileName: string): void {
258+
if (!this.compiledModules.hasOwnProperty(fileName)) {
259+
this.clearCompiledModules(fileName);
260+
}
261+
262+
let store = this.compiledModules[fileName];
263+
264+
if (store.indexOf(depFileName) === -1) {
265+
store.push(depFileName);
266+
}
267+
}
268+
254269
clearDependencies(fileName: string): void {
255270
this.dependencies[fileName] = []
256271
}
257272

273+
clearCompiledModules(fileName: string): void {
274+
this.compiledModules[fileName] = []
275+
}
276+
258277
getDependencies(fileName: string): string[] {
259278
if (!this.dependencies.hasOwnProperty(fileName)) {
260279
this.clearDependencies(fileName);
@@ -317,6 +336,16 @@ export class DependencyManager {
317336
return result.buf += '\n\n';
318337
}
319338

339+
applyCompiledFiles(fileName: string, deps: IDependency) {
340+
if (!this.compiledModules.hasOwnProperty(fileName)) {
341+
this.clearCompiledModules(fileName);
342+
}
343+
344+
this.compiledModules[fileName].forEach((mod) => {
345+
deps.add(mod)
346+
})
347+
}
348+
320349
applyChain(fileName: string, deps: IDependency) {
321350
if (!this.dependencies.hasOwnProperty(fileName)) {
322351
this.clearDependencies(fileName);
@@ -354,6 +383,36 @@ export class ValidFilesManager {
354383
}
355384
}
356385

386+
export interface CompiledModule {
387+
fileName: string,
388+
text: string,
389+
map?: string,
390+
mapName?: string
391+
}
392+
393+
export function findCompiledModule(fileName: string): CompiledModule {
394+
let baseFileName = fileName.replace(/(\.ts|\.tsx)$/, '');
395+
let compiledFileName = `${baseFileName}.js`
396+
397+
if (fs.existsSync(compiledFileName)) {
398+
let mapFileName = `${baseFileName}.js.map`;
399+
let isMapExists = fs.existsSync(mapFileName);
400+
let result = {
401+
fileName: compiledFileName,
402+
text: fs.readFileSync(compiledFileName).toString(),
403+
mapName: isMapExists
404+
? mapFileName
405+
: null,
406+
map: isMapExists
407+
? fs.readFileSync(mapFileName).toString()
408+
: null
409+
}
410+
return result;
411+
} else {
412+
return null;
413+
}
414+
}
415+
357416
/**
358417
* Emit compilation result for a specified fileName.
359418
*/

src/host.ts

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export interface ICompilerOptions extends ts.CompilerOptions {
3838
externals?: any;
3939
doTypeCheck?: boolean;
4040
forkChecker?: boolean;
41+
useBabel?: boolean;
4142
}
4243

4344
export interface IOutputFile extends ts.OutputFile {

src/index.ts

+59-13
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as childProcess from 'child_process';
99
import * as colors from 'colors';
1010

1111
import { ICompilerOptions, TypeScriptCompilationError, State, ICompilerInfo } from './host';
12-
import { IResolver, ResolutionError } from './deps';
12+
import { IResolver, ResolutionError, findCompiledModule } from './deps';
1313
import * as helpers from './helpers';
1414
import { loadLib } from './helpers';
1515

@@ -39,6 +39,7 @@ interface IWebPack {
3939
interface ICompilerInstance {
4040
tsFlow: Promise<any>;
4141
tsState: State;
42+
babelImpl?: any;
4243
compiledFiles: {[key:string]: boolean};
4344
options: ICompilerOptions;
4445
externalsInvoked: boolean;
@@ -106,6 +107,10 @@ const COMPILER_ERROR = colors.red(`\n\nTypescript compiler cannot be found, plea
106107
npm install --save-dev typescript
107108
`);
108109

110+
const BABEL_ERROR = colors.red(`\n\nBabel compiler cannot be found, please add it to your package.json file:
111+
npm install --save-dev babel
112+
`);
113+
109114
/**
110115
* Creates compiler instance
111116
*/
@@ -223,6 +228,16 @@ function ensureInstance(webpack: IWebPack, options: ICompilerOptions, instanceNa
223228
options.target = helpers.parseOptionTarget(<any>options.target, tsImpl);
224229
}
225230

231+
let babelImpl: any;
232+
if (options.useBabel) {
233+
try {
234+
babelImpl = require(path.join(process.cwd(), 'node_modules', 'babel'));
235+
} catch (e) {
236+
console.error(BABEL_ERROR);
237+
process.exit(1);
238+
}
239+
}
240+
226241
let tsState = new State(options, webpack._compiler.inputFileSystem, compilerInfo);
227242
let compiler = (<any>webpack._compiler);
228243

@@ -301,6 +316,7 @@ function ensureInstance(webpack: IWebPack, options: ICompilerOptions, instanceNa
301316
return getInstanceStore(webpack._compiler)[instanceName] = {
302317
tsFlow,
303318
tsState,
319+
babelImpl,
304320
compiledFiles: {},
305321
options,
306322
externalsInvoked: false,
@@ -330,6 +346,7 @@ function compiler(webpack: IWebPack, text: string): void {
330346
let fileName = webpack.resourcePath;
331347

332348
let resolver = createResolver(webpack._compiler, webpack.resolve);
349+
let isDepsApplied = false;
333350

334351
let depsInjector = {
335352
add: (depFileName) => {webpack.addDependency(depFileName)},
@@ -339,6 +356,7 @@ function compiler(webpack: IWebPack, text: string): void {
339356
let applyDeps = _.once(() => {
340357
depsInjector.clear();
341358
depsInjector.add(fileName);
359+
state.fileAnalyzer.dependencies.applyCompiledFiles(fileName, depsInjector);
342360
if (state.options.reEmitDependentFiles) {
343361
state.fileAnalyzer.dependencies.applyChain(fileName, depsInjector);
344362
}
@@ -370,31 +388,59 @@ function compiler(webpack: IWebPack, text: string): void {
370388
});
371389
})
372390
.then(() => {
373-
return state.emit(fileName)
374-
})
375-
.then(output => {
376-
let result = helpers.findResultFor(output, fileName);
391+
let resultText;
392+
let resultSourceMap;
393+
394+
let compiledModule = findCompiledModule(fileName);
395+
if (compiledModule) {
396+
state.fileAnalyzer.dependencies.addCompiledModule(fileName, compiledModule.fileName);
397+
resultText = compiledModule.text;
398+
resultSourceMap = JSON.parse(compiledModule.map);
399+
} else {
400+
let output = state.emit(fileName);
401+
let result = helpers.findResultFor(output, fileName);
377402

378-
if (result.text === undefined) {
379-
throw new Error('no output found for ' + fileName);
403+
if (result.text === undefined) {
404+
throw new Error('No output found for ' + fileName);
405+
}
406+
407+
resultText = result.text;
408+
resultSourceMap = JSON.parse(result.sourceMap);
409+
resultSourceMap.sources = [ fileName ];
410+
resultSourceMap.file = fileName;
411+
resultSourceMap.sourcesContent = [ text ];
412+
413+
if (instance.options.useBabel) {
414+
let defaultOptions = {
415+
inputSourceMap: resultSourceMap,
416+
filename: fileName,
417+
sourceMap: true
418+
}
419+
420+
let babelResult = instance.babelImpl.transform(resultText, defaultOptions);
421+
resultText = babelResult.code;
422+
resultSourceMap = babelResult.map;
423+
}
380424
}
381425

382-
let sourceMap = JSON.parse(result.sourceMap);
383-
sourceMap.sources = [ fileName ];
384-
sourceMap.file = fileName;
385-
sourceMap.sourcesContent = [ text ];
426+
resultSourceMap.sources = [ fileName ];
427+
resultSourceMap.file = fileName;
428+
resultSourceMap.sourcesContent = [ text ];
386429

387430
applyDeps();
431+
isDepsApplied = true;
388432

389433
try {
390-
callback(null, result.text, sourceMap);
434+
callback(null, resultText, resultSourceMap)
391435
} catch (e) {
392436
console.error('Error in bail mode:', e);
393437
process.exit(1);
394438
}
395439
})
396440
.finally(() => {
397-
applyDeps();
441+
if (!isDepsApplied) {
442+
applyDeps();
443+
}
398444
})
399445
.catch(ResolutionError, err => {
400446
callback(err, helpers.codegenErrorReport([err]));

webpack.backend.config.js

-5
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,6 @@ module.exports = {
4545
test: /\.ts$/,
4646
loader: "awesome-typescript?rewriteImports=alfa-react-ui&externals=" + typeLib
4747
},
48-
{
49-
test: /\.js$/,
50-
exclude: /(node_modules|bower_components)/,
51-
loader: 'babel-loader'
52-
},
5348
{
5449
test: /\.json$/,
5550
loader: "json-loader"

0 commit comments

Comments
 (0)