UNPKG

5.77 kBPlain TextView Raw
1import * as _ from 'lodash';
2import * as path from 'path';
3
4import { findCompiledModule, cache } from './cache';
5import * as helpers from './helpers';
6import { QueryOptions, Loader, ensureInstance, Instance, getRootCompiler } from './instance';
7import { PathPlugin } from './paths-plugin';
8import { CheckerPlugin as _CheckerPlugin } from './watch-mode';
9
10const loaderUtils = require('loader-utils');
11
12function loader(text) {
13 try {
14 compiler.call(undefined, this, text);
15 } catch(e) {
16 console.error(e, e.stack);
17 throw e;
18 }
19}
20
21namespace loader {
22 export const TsConfigPathsPlugin = PathPlugin;
23 export const CheckerPlugin = _CheckerPlugin;
24}
25
26interface Transformation {
27 text: string;
28 map: any;
29 deps: string[];
30 fresh?: boolean;
31}
32
33const DECLARATION = /\.d.ts$/i;
34
35function compiler(loader: Loader, text: string): void {
36 if (loader.cacheable) {
37 loader.cacheable();
38 }
39
40 const rootCompiler = getRootCompiler(loader._compiler);
41
42 const query = <QueryOptions>(loaderUtils.getOptions(loader) || {});
43 const options = (loader.options && loader.options.ts) || {};
44 const instanceName = query.instance || 'at-loader';
45 const instance = ensureInstance(loader, query, options, instanceName, rootCompiler);
46 const callback = loader.async();
47
48 let fileName = helpers.toUnix(loader.resourcePath);
49 instance.compiledFiles[fileName] = true;
50
51 if (DECLARATION.test(fileName)) {
52 loader.emitWarning(`[${instanceName}] TypeScript declaration files should never be required`);
53 return callback(null, '');
54 }
55
56 let compiledModule;
57 if (instance.loaderConfig.usePrecompiledFiles) {
58 compiledModule = findCompiledModule(fileName);
59 }
60
61 let transformation: Promise<{cached: boolean, result: Transformation}> = null;
62
63 if (compiledModule) {
64 transformation = Promise.resolve({
65 text: compiledModule.text,
66 map: compiledModule.map
67 ? JSON.parse(compiledModule.map)
68 : null
69 }).then(result => ({cached: true, result}));
70 } else {
71 const transformationFunction = () => transform(
72 loader,
73 instance,
74 fileName,
75 text
76 );
77
78 if (instance.loaderConfig.useCache) {
79 transformation = cache<Transformation>({
80 source: text,
81 identifier: instance.cacheIdentifier,
82 directory: instance.loaderConfig.cacheDirectory,
83 options: loader.query,
84 transform: transformationFunction
85 });
86 } else {
87 transformation = transformationFunction().then(result => ({cached: false, result}));
88 }
89 }
90
91 transformation
92 .then(({cached, result}) => {
93 if (!instance.compilerConfig.options.isolatedModules && result.deps) {
94 // If our modules are isolated we don't need to recompile all the deps
95 result.deps.forEach(dep => loader.addDependency(path.normalize(dep)));
96 }
97 if (cached) {
98 // Update file in checker in case we read it from the cache
99 instance.checker.updateFile(fileName, text);
100 }
101 return result;
102 })
103 .then(({text, map}) => {
104 callback(null, text, map);
105 })
106 .catch(callback)
107 .catch(e => {
108 console.error('Error in bail mode:', e, e.stack.join
109 ? e.stack.join ('\n')
110 : e.stack
111 );
112 process.exit(1);
113 });
114}
115
116function transform(
117 webpack: Loader,
118 instance: Instance,
119 fileName: string,
120 text: string
121): Promise<Transformation> {
122 let resultText;
123 let resultSourceMap = null;
124
125 return instance.checker.emitFile(fileName, text).then((({emitResult, deps}) => {
126 resultSourceMap = emitResult.sourceMap;
127 resultText = emitResult.text;
128
129 let sourceFileName = fileName.replace(instance.context + '/', '');
130 if (resultSourceMap) {
131 resultSourceMap = JSON.parse(resultSourceMap);
132 resultSourceMap.sources = [ sourceFileName ];
133 resultSourceMap.file = sourceFileName;
134 resultSourceMap.sourcesContent = [ text ];
135
136 resultText = resultText.replace(/^\/\/# sourceMappingURL=[^\r\n]*/gm, '');
137 }
138
139 if (instance.loaderConfig.useBabel) {
140 let defaultOptions = {
141 inputSourceMap: resultSourceMap,
142 sourceRoot: instance.context,
143 filename: fileName,
144 sourceMap: true
145 };
146
147 let babelOptions = _.assign({}, defaultOptions, instance.loaderConfig.babelOptions);
148 let babelResult = instance.babelImpl.transform(resultText, babelOptions);
149
150 resultText = babelResult.code;
151 resultSourceMap = babelResult.map;
152 }
153
154 if (resultSourceMap) {
155 let sourcePath = path.relative(
156 instance.compilerConfig.options.sourceRoot || instance.context,
157 loaderUtils.getRemainingRequest(webpack)
158 );
159
160 resultSourceMap.sources = [ sourcePath ];
161 resultSourceMap.file = fileName;
162 resultSourceMap.sourcesContent = [ text ];
163 }
164
165 if (emitResult.declaration) {
166 const declPath = path.relative(
167 instance.context,
168 emitResult.declaration.name
169 );
170
171 webpack.emitFile(
172 declPath,
173 emitResult.declaration.text
174 );
175 }
176
177 return {
178 text: resultText,
179 map: resultSourceMap,
180 deps,
181 };
182 }));
183}
184
185export = loader;
186
\No newline at end of file