Skip to content

Commit fe10a56

Browse files
Merge pull request #69 from privatenumber/develop
release
2 parents 23f2a00 + aa3ad60 commit fe10a56

File tree

4 files changed

+281
-1
lines changed

4 files changed

+281
-1
lines changed

src/loader.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import {getOptions} from 'loader-utils';
22
import webpack4 = require('webpack');
33
import {Compiler, LoaderOptions} from './interfaces';
44

5+
const tsxTryTsLoaderPtrn = /Unexpected|Expected/;
6+
57
async function ESBuildLoader(
68
this: webpack4.loader.LoaderContext,
79
source: string,
@@ -29,7 +31,7 @@ async function ESBuildLoader(
2931
try {
3032
const result = await service.transform(source, transformOptions).catch(async error => {
3133
// Target might be a TS file accidentally parsed as TSX
32-
if (transformOptions.loader === 'tsx' && error.message.includes('Unexpected')) {
34+
if (transformOptions.loader === 'tsx' && tsxTryTsLoaderPtrn.test(error.message)) {
3335
transformOptions.loader = 'ts';
3436
return service.transform(source, transformOptions).catch(_ => {
3537
throw error;

test/__snapshots__/loader.test.ts.snap

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,134 @@ const usePrevious = (value) => {
400400
/* harmony default export */ __webpack_exports__[\\"default\\"] = (usePrevious);
401401
402402
403+
/***/ })
404+
405+
/******/ });"
406+
`;
407+
408+
exports[`Webpack 4 Loader ts as tsx 2 1`] = `
409+
"module.exports =
410+
/******/ (function(modules) { // webpackBootstrap
411+
/******/ // The module cache
412+
/******/ var installedModules = {};
413+
/******/
414+
/******/ // The require function
415+
/******/ function __webpack_require__(moduleId) {
416+
/******/
417+
/******/ // Check if module is in cache
418+
/******/ if(installedModules[moduleId]) {
419+
/******/ return installedModules[moduleId].exports;
420+
/******/ }
421+
/******/ // Create a new module (and put it into the cache)
422+
/******/ var module = installedModules[moduleId] = {
423+
/******/ i: moduleId,
424+
/******/ l: false,
425+
/******/ exports: {}
426+
/******/ };
427+
/******/
428+
/******/ // Execute the module function
429+
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
430+
/******/
431+
/******/ // Flag the module as loaded
432+
/******/ module.l = true;
433+
/******/
434+
/******/ // Return the exports of the module
435+
/******/ return module.exports;
436+
/******/ }
437+
/******/
438+
/******/
439+
/******/ // expose the modules object (__webpack_modules__)
440+
/******/ __webpack_require__.m = modules;
441+
/******/
442+
/******/ // expose the module cache
443+
/******/ __webpack_require__.c = installedModules;
444+
/******/
445+
/******/ // define getter function for harmony exports
446+
/******/ __webpack_require__.d = function(exports, name, getter) {
447+
/******/ if(!__webpack_require__.o(exports, name)) {
448+
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
449+
/******/ }
450+
/******/ };
451+
/******/
452+
/******/ // define __esModule on exports
453+
/******/ __webpack_require__.r = function(exports) {
454+
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
455+
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
456+
/******/ }
457+
/******/ Object.defineProperty(exports, '__esModule', { value: true });
458+
/******/ };
459+
/******/
460+
/******/ // create a fake namespace object
461+
/******/ // mode & 1: value is a module id, require it
462+
/******/ // mode & 2: merge all properties of value into the ns
463+
/******/ // mode & 4: return value when already ns object
464+
/******/ // mode & 8|1: behave like require
465+
/******/ __webpack_require__.t = function(value, mode) {
466+
/******/ if(mode & 1) value = __webpack_require__(value);
467+
/******/ if(mode & 8) return value;
468+
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
469+
/******/ var ns = Object.create(null);
470+
/******/ __webpack_require__.r(ns);
471+
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
472+
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
473+
/******/ return ns;
474+
/******/ };
475+
/******/
476+
/******/ // getDefaultExport function for compatibility with non-harmony modules
477+
/******/ __webpack_require__.n = function(module) {
478+
/******/ var getter = module && module.__esModule ?
479+
/******/ function getDefault() { return module['default']; } :
480+
/******/ function getModuleExports() { return module; };
481+
/******/ __webpack_require__.d(getter, 'a', getter);
482+
/******/ return getter;
483+
/******/ };
484+
/******/
485+
/******/ // Object.prototype.hasOwnProperty.call
486+
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
487+
/******/
488+
/******/ // __webpack_public_path__
489+
/******/ __webpack_require__.p = \\"\\";
490+
/******/
491+
/******/
492+
/******/ // Load entry module and return exports
493+
/******/ return __webpack_require__(__webpack_require__.s = \\"./index.js\\");
494+
/******/ })
495+
/************************************************************************/
496+
/******/ ({
497+
498+
/***/ \\"./index.js\\":
499+
/*!*****************!*\\\\
500+
!*** /index.js ***!
501+
\\\\*****************/
502+
/*! no exports provided */
503+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
504+
505+
\\"use strict\\";
506+
__webpack_require__.r(__webpack_exports__);
507+
/* harmony import */ var _use_previous_ts__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../use-previous.ts */ \\"./use-previous.ts\\");
508+
509+
console.log(_use_previous_ts__WEBPACK_IMPORTED_MODULE_0__[\\"default\\"]);
510+
511+
512+
/***/ }),
513+
514+
/***/ \\"./use-previous.ts\\":
515+
/*!************************!*\\\\
516+
!*** /use-previous.ts ***!
517+
\\\\************************/
518+
/*! exports provided: default */
519+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
520+
521+
\\"use strict\\";
522+
__webpack_require__.r(__webpack_exports__);
523+
class Foo {
524+
}
525+
const testFn = (l, options) => {
526+
return options[l];
527+
};
528+
/* harmony default export */ __webpack_exports__[\\"default\\"] = (testFn);
529+
530+
403531
/***/ })
404532
405533
/******/ });"
@@ -2061,6 +2189,116 @@ const usePrevious = (value) => {
20612189
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (usePrevious);
20622190
20632191
2192+
/***/ })
2193+
2194+
/******/ });
2195+
/************************************************************************/
2196+
/******/ // The module cache
2197+
/******/ var __webpack_module_cache__ = {};
2198+
/******/
2199+
/******/ // The require function
2200+
/******/ function __webpack_require__(moduleId) {
2201+
/******/ // Check if module is in cache
2202+
/******/ if(__webpack_module_cache__[moduleId]) {
2203+
/******/ return __webpack_module_cache__[moduleId].exports;
2204+
/******/ }
2205+
/******/ // Create a new module (and put it into the cache)
2206+
/******/ var module = __webpack_module_cache__[moduleId] = {
2207+
/******/ // no module.id needed
2208+
/******/ // no module.loaded needed
2209+
/******/ exports: {}
2210+
/******/ };
2211+
/******/
2212+
/******/ // Execute the module function
2213+
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
2214+
/******/
2215+
/******/ // Return the exports of the module
2216+
/******/ return module.exports;
2217+
/******/ }
2218+
/******/
2219+
/************************************************************************/
2220+
/******/ /* webpack/runtime/define property getters */
2221+
/******/ (() => {
2222+
/******/ // define getter functions for harmony exports
2223+
/******/ __webpack_require__.d = (exports, definition) => {
2224+
/******/ for(var key in definition) {
2225+
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
2226+
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
2227+
/******/ }
2228+
/******/ }
2229+
/******/ };
2230+
/******/ })();
2231+
/******/
2232+
/******/ /* webpack/runtime/hasOwnProperty shorthand */
2233+
/******/ (() => {
2234+
/******/ __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
2235+
/******/ })();
2236+
/******/
2237+
/******/ /* webpack/runtime/make namespace object */
2238+
/******/ (() => {
2239+
/******/ // define __esModule on exports
2240+
/******/ __webpack_require__.r = (exports) => {
2241+
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
2242+
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2243+
/******/ }
2244+
/******/ Object.defineProperty(exports, '__esModule', { value: true });
2245+
/******/ };
2246+
/******/ })();
2247+
/******/
2248+
/************************************************************************/
2249+
/******/ // module exports must be returned from runtime so entry inlining is disabled
2250+
/******/ // startup
2251+
/******/ // Load entry module and return exports
2252+
/******/ return __webpack_require__(\\"./index.js\\");
2253+
/******/ })()
2254+
;"
2255+
`;
2256+
2257+
exports[`Webpack 5 Loader ts as tsx 2 1`] = `
2258+
"module.exports =
2259+
/******/ (() => { // webpackBootstrap
2260+
/******/ \\"use strict\\";
2261+
/******/ var __webpack_modules__ = ({
2262+
2263+
/***/ \\"./index.js\\":
2264+
/*!******************!*\\\\
2265+
!*** ./index.js ***!
2266+
\\\\******************/
2267+
/*! namespace exports */
2268+
/*! exports [not provided] [maybe used in index (runtime-defined)] */
2269+
/*! runtime requirements: __webpack_require__, __webpack_require__.r, __webpack_exports__, __webpack_require__.* */
2270+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2271+
2272+
__webpack_require__.r(__webpack_exports__);
2273+
/* harmony import */ var _use_previous_ts__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./use-previous.ts */ \\"./use-previous.ts\\");
2274+
2275+
console.log(_use_previous_ts__WEBPACK_IMPORTED_MODULE_0__.default);
2276+
2277+
2278+
/***/ }),
2279+
2280+
/***/ \\"./use-previous.ts\\":
2281+
/*!*************************!*\\\\
2282+
!*** ./use-previous.ts ***!
2283+
\\\\*************************/
2284+
/*! namespace exports */
2285+
/*! export default [provided] [no usage info] [missing usage info prevents renaming] */
2286+
/*! other exports [not provided] [no usage info] */
2287+
/*! runtime requirements: __webpack_exports__, __webpack_require__.r, __webpack_require__.d, __webpack_require__.* */
2288+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2289+
2290+
__webpack_require__.r(__webpack_exports__);
2291+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
2292+
/* harmony export */ \\"default\\": () => __WEBPACK_DEFAULT_EXPORT__
2293+
/* harmony export */ });
2294+
class Foo {
2295+
}
2296+
const testFn = (l, options) => {
2297+
return options[l];
2298+
};
2299+
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (testFn);
2300+
2301+
20642302
/***/ })
20652303
20662304
/******/ });

test/fixtures.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ export const ts = {
3636
`,
3737
};
3838

39+
export const ts2 = {
40+
'/index.js': `
41+
import usePrevious from './use-previous.ts'
42+
console.log(usePrevious)
43+
`,
44+
45+
'/use-previous.ts': `
46+
class Foo { foo }
47+
48+
const testFn = <V>(
49+
l: Level,
50+
options: { [key in Level]: V },
51+
): V => {
52+
return options[l];
53+
};
54+
55+
export default testFn;
56+
`,
57+
};
58+
3959
export const tsx = {
4060
'/index.js': `
4161
import Foo from './foo.tsx'

test/loader.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ describe.each([
7373

7474
test('ts as tsx', async () => {
7575
/*
76+
* Catch errror "Transform failed with 1 error:\n/use-previous.ts:5:2: error: Unexpected \"const\""
7677
* If a TS file is accidentally parsed as TSX, it should fallback to parsing as TS
7778
* This is to support ts-loader like syntax: test: /\.tsx?$/
7879
*/
@@ -89,6 +90,25 @@ describe.each([
8990
expect(getFile(stats, '/dist/index.js')).toMatchSnapshot();
9091
});
9192

93+
test('ts as tsx 2', async () => {
94+
/*
95+
* Catch errror "Transform failed with 1 error:\n/use-previous.ts:5:27: error: Expected \"}\" but found \":\""
96+
* If a TS file is accidentally parsed as TSX, it should fallback to parsing as TS
97+
* This is to support ts-loader like syntax: test: /\.tsx?$/
98+
*/
99+
const stats = await build(webpack, fixtures.ts2, config => {
100+
config.module.rules.push({
101+
test: /\.tsx?$/,
102+
loader: 'esbuild-loader',
103+
options: {
104+
loader: 'tsx',
105+
},
106+
});
107+
});
108+
109+
expect(getFile(stats, '/dist/index.js')).toMatchSnapshot();
110+
});
111+
92112
test('ts w/ tsconfig', async () => {
93113
const stats = await build(webpack, fixtures.ts, config => {
94114
config.module.rules.push({

0 commit comments

Comments
 (0)