Skip to content

Commit

Permalink
Apply other loaders when updating files in watch mode (#1115)
Browse files Browse the repository at this point in the history
* Apply other loaders when updating changed files

* Use 'loadModule' instead of 'runLoaders'

* add a stringify loader

* Add a comment to updateFile

* v7.0.5
  • Loading branch information
iorate authored May 24, 2020
1 parent 1b84fed commit d187a7c
Show file tree
Hide file tree
Showing 24 changed files with 806 additions and 15 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## v7.0.5
* [Apply other loaders when updating files in watch mode](https://github.com/TypeStrong/ts-loader/pull/1115) - thanks @iorate

## v7.0.4
* [Ensure a separate webpack instance is created for different loader options](https://github.com/TypeStrong/ts-loader/pull/1104) - thanks @appzuka

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ts-loader",
"version": "7.0.4",
"version": "7.0.5",
"description": "TypeScript loader for webpack",
"main": "index.js",
"types": "dist",
Expand Down
4 changes: 2 additions & 2 deletions src/instances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ export function initializeInstance(
);
loader._compiler.hooks.watchRun.tapAsync(
'ts-loader',
makeWatchRun(instance)
makeWatchRun(instance, loader)
);
}
} else {
Expand Down Expand Up @@ -345,7 +345,7 @@ export function initializeInstance(
);
loader._compiler.hooks.watchRun.tapAsync(
'ts-loader',
makeWatchRun(instance)
makeWatchRun(instance, loader)
);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/stringify-loader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = (source: string) => JSON.stringify(source);
66 changes: 54 additions & 12 deletions src/watch-run.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as path from 'path';
import * as webpack from 'webpack';

import * as constants from './constants';
Expand All @@ -8,12 +9,19 @@ import { readFile } from './utils';
/**
* Make function which will manually update changed files
*/
export function makeWatchRun(instance: TSInstance) {
export function makeWatchRun(
instance: TSInstance,
loader: webpack.loader.LoaderContext
) {
// Called Before starting compilation after watch
const lastTimes = new Map<string, number>();
const startTime = 0;

return (compiler: webpack.Compiler, callback: () => void) => {
// Save the loader index.
const loaderIndex = loader.loaderIndex;

return (compiler: webpack.Compiler, callback: (err?: Error) => void) => {
const promises = [];
if (instance.loaderOptions.transpileOnly) {
instance.reportTranspileErrors = true;
} else {
Expand All @@ -27,7 +35,7 @@ export function makeWatchRun(instance: TSInstance) {
}

lastTimes.set(filePath, date);
updateFile(instance, filePath);
promises.push(updateFile(instance, filePath, loader, loaderIndex));
}

// On watch update add all known dts files expect the ones in node_modules
Expand All @@ -37,26 +45,60 @@ export function makeWatchRun(instance: TSInstance) {
filePath.match(constants.dtsDtsxOrDtsDtsxMapRegex) !== null &&
filePath.match(constants.nodeModules) === null
) {
updateFile(instance, filePath);
promises.push(updateFile(instance, filePath, loader, loaderIndex));
}
}
}

// Update all the watched files from solution builder
if (instance.solutionBuilderHost) {
for (const filePath of instance.solutionBuilderHost.watchedFiles.keys()) {
updateFile(instance, filePath);
promises.push(updateFile(instance, filePath, loader, loaderIndex));
}
}

callback();
Promise.all(promises)
.then(() => callback())
.catch(err => callback(err));
};
}

function updateFile(instance: TSInstance, filePath: string) {
updateFileWithText(
instance,
filePath,
nFilePath => readFile(nFilePath) || ''
);
function updateFile(
instance: TSInstance,
filePath: string,
loader: webpack.loader.LoaderContext,
loaderIndex: number
) {
return new Promise<void>((resolve, reject) => {
// When other loaders are specified after ts-loader
// (e.g. `{ test: /\.ts$/, use: ['ts-loader', 'other-loader'] }`),
// manually apply them to TypeScript files.
// Otherwise, files not 'preprocessed' by them may cause complication errors (#1111).
if (
loaderIndex + 1 < loader.loaders.length &&
instance.rootFileNames.has(path.normalize(filePath))
) {
let request = `!!${path.resolve(__dirname, 'stringify-loader.js')}!`;
for (let i = loaderIndex + 1; i < loader.loaders.length; ++i) {
request += loader.loaders[i].request + '!';
}
request += filePath;
loader.loadModule(request, (err, source) => {
if (err) {
reject(err);
} else {
const text = JSON.parse(source);
updateFileWithText(instance, filePath, () => text);
resolve();
}
});
} else {
updateFileWithText(
instance,
filePath,
nFilePath => readFile(nFilePath) || ''
);
resolve();
}
});
}
2 changes: 2 additions & 0 deletions test/comparison-tests/otherLoadersWatch/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { message } from './message';
console.log(message);
113 changes: 113 additions & 0 deletions test/comparison-tests/otherLoadersWatch/expectedOutput-3.8/bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./app.ts");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./app.ts":
/*!****************!*\
!*** ./app.ts ***!
\****************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nexports.__esModule = true;\nvar message_1 = __webpack_require__(/*! ./message */ \"./message.ts\");\nconsole.log(message_1.message);\n\n\n//# sourceURL=webpack:///./app.ts?");

/***/ }),

/***/ "./message.ts":
/*!********************!*\
!*** ./message.ts ***!
\********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nexports.__esModule = true;\nexports.message = 'Hello, world!';\n\n\n//# sourceURL=webpack:///./message.ts?");

/***/ })

/******/ });
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Asset Size Chunks Chunk Names
bundle.js 4.22 KiB main [emitted] main
Entrypoint main = bundle.js
[./app.ts] 111 bytes {main} [built]
[./message.ts] 76 bytes {main} [built]
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./app.ts");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./app.ts":
/*!****************!*\
!*** ./app.ts ***!
\****************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nexports.__esModule = true;\nvar message_1 = __webpack_require__(/*! ./message */ \"./message.ts\");\nconsole.log(message_1.message);\n\n\n//# sourceURL=webpack:///./app.ts?");

/***/ }),

/***/ "./message.ts":
/*!********************!*\
!*** ./message.ts ***!
\********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nexports.__esModule = true;\nexports.message = 'Hello, world!';\n\n\n//# sourceURL=webpack:///./message.ts?");

/***/ })

/******/ });
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Asset Size Chunks Chunk Names
bundle.js 4.22 KiB main [emitted] main
Entrypoint main = bundle.js
[./app.ts] 111 bytes {main} [built]
[./message.ts] 76 bytes {main}
Loading

0 comments on commit d187a7c

Please sign in to comment.