1 | import * as _ from 'lodash';
|
2 | import * as path from 'path';
|
3 |
|
4 | import { findCompiledModule, cache } from './cache';
|
5 | import * as helpers from './helpers';
|
6 | import { QueryOptions, Loader, ensureInstance, Instance, getRootCompiler } from './instance';
|
7 | import { PathPlugin } from './paths-plugin';
|
8 | import { CheckerPlugin as _CheckerPlugin } from './watch-mode';
|
9 |
|
10 | const loaderUtils = require('loader-utils');
|
11 |
|
12 | function 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 |
|
21 | namespace loader {
|
22 | export const TsConfigPathsPlugin = PathPlugin;
|
23 | export const CheckerPlugin = _CheckerPlugin;
|
24 | }
|
25 |
|
26 | interface Transformation {
|
27 | text: string;
|
28 | map: any;
|
29 | deps: string[];
|
30 | fresh?: boolean;
|
31 | }
|
32 |
|
33 | const DECLARATION = /\.d.ts$/i;
|
34 |
|
35 | function 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 |
|
95 | result.deps.forEach(dep => loader.addDependency(path.normalize(dep)));
|
96 | }
|
97 | if (cached) {
|
98 |
|
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 |
|
116 | function 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 |
|
185 | export = loader;
|
186 |
|
\ | No newline at end of file |