Skip to content

Commit

Permalink
Add allowTsInNodeModules option for importing .ts files from node_mod…
Browse files Browse the repository at this point in the history
…ules. (#773)

* Add allowTsInNodeModules loader option.

* Add error text for allowTsInNodeModules option when importing .ts files
from node_modules.
Tweak existing error text and code style.

* Update nodeModulesMeaningfulErrorWhenImportingTs test outputs.

* Add test for enabling allowTsInNodeModules option.

* Add option description to README.md

* Change allowTsInNodeModules from comparison test to execution test.
Add tests for successful import of module and file.

* Fix indentation.
Remove webpack output during karma tests.

* Linkify GitHub issue reference.
Add better example for tsconfig.json.

* Update error message logic to use ternary.

* Slight change in output for nodeModulesMeaningfulErrorWhenImportingTs
comparison test.
  • Loading branch information
aelawson authored and johnnyreilly committed May 7, 2018
1 parent ec679ed commit a150671
Show file tree
Hide file tree
Showing 20 changed files with 208 additions and 22 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,37 @@ loading only those files that are actually bundled by webpack, as well as any `.
by the `tsconfig.json` settings. `.d.ts` files are still included because they may be needed for
compilation without being explicitly imported, and therefore not picked up by webpack.

#### allowTsInNodeModules _(boolean) (default=false)_

By default, ts-loader will not compile `.ts` files in `node_modules`.
You should not need to recompile `.ts` files there, but if you really want to, use this option.
Note that this option acts as a *whitelist* - any modules you desire to import must be included in
the `"files"` or `"include"` block of your project's `tsconfig.json`.

See: [https://github.com/Microsoft/TypeScript/issues/12358](https://github.com/Microsoft/TypeScript/issues/12358)

```javascript
// in webpack.config.js
{
test: /\.ts$/,
loader: 'ts-loader',
options: { allowTsInNodeModules: true }
}
```

And in your `tsconfig.json`:

```json
{
"include": [
"node_modules/whitelisted_module.ts"
],
"files": [
"node_modules/my_module/whitelisted_file.ts"
]
}
```

#### context _(string) (default=undefined)_

If set, will parse the TypeScript configuration file with given **absolute path** as base path.
Expand Down
16 changes: 10 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,12 @@ function successLoader(
: getEmit(rawFilePath, filePath, instance, loader);

if (outputText === null || outputText === undefined) {
const additionalGuidance =
filePath.indexOf('node_modules') !== -1
? '\nYou should not need to recompile .ts files in node_modules.\nPlease contact the package author to advise them to use --declaration --outDir.\nMore https://github.com/Microsoft/TypeScript/issues/12358'
: '';
const additionalGuidance: string = (!options.allowTsInNodeModules && filePath.indexOf('node_modules') !== -1)
? " By default, ts-loader will not compile .ts files in node_modules.\n" +
"You should not need to recompile .ts files there, but if you really want to, use the allowTsInNodeModules option.\n" +
"See: https://github.com/Microsoft/TypeScript/issues/12358"
: "";

throw new Error(
`Typescript emitted no output for ${filePath}.${additionalGuidance}`
);
Expand Down Expand Up @@ -147,7 +149,8 @@ const validLoaderOptions: ValidLoaderOptions[] = [
'happyPackMode',
'getCustomTransformers',
'reportFiles',
'experimentalWatchApi'
'experimentalWatchApi',
'allowTsInNodeModules'
];

/**
Expand Down Expand Up @@ -199,7 +202,8 @@ function makeLoaderOptions(instanceName: string, loaderOptions: LoaderOptions) {
onlyCompileBundledFiles: false,
reportFiles: [],
// When the watch API usage stabilises look to remove this option and make watch usage the default behaviour when available
experimentalWatchApi: false
experimentalWatchApi: false,
allowTsInNodeModules: false
} as Partial<LoaderOptions>,
loaderOptions
);
Expand Down
1 change: 1 addition & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ export interface LoaderOptions {
| string
| (() => typescript.CustomTransformers | undefined);
experimentalWatchApi: boolean;
allowTsInNodeModules: boolean;
}

export interface TSFile {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ eval("\nexports.__esModule = true;\nvar a = __webpack_require__(/*! a */ \"./nod
/*! no static exports found */
/***/ (function(module, exports) {

eval("throw new Error(\"Module build failed: Error: Typescript emitted no output for C://source//ts-loader//.test//nodeModulesMeaningfulErrorWhenImportingTs//node_modules//a//index.ts./nYou should not need to recompile .ts files in node_modules./nPlease contact the package author to advise them to use --declaration --outDir./nMore https://github.com/Microsoft/TypeScript/issues/12358/n at successLoader (C://source//ts-loader//dist//index.js:39:15)/n at Object.loader (C://source//ts-loader//dist//index.js:21:12)\");\n\n//# sourceURL=webpack:///./node_modules/a/index.ts?");
eval("throw new Error(\"Module build failed: Error: Typescript emitted no output for /nodeModulesMeaningfulErrorWhenImportingTs/node_modules/a/index.ts. By default, ts-loader will not compile .ts files in node_modules./nYou should not need to recompile .ts files there, but if you really want to, use the allowTsInNodeModules option./nSee: https://github.com/Microsoft/TypeScript/issues/12358/n at successLoader (/Users/alawson/dev/ts-loader/dist/index.js:41:15)/n at Object.loader (/Users/alawson/dev/ts-loader/dist/index.js:21:12)\");\n\n//# sourceURL=webpack:///./node_modules/a/index.ts?");

/***/ })

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
Asset Size Chunks Chunk Names
bundle.js 3.75 KiB main [emitted] main
bundle.js 3.77 KiB main [emitted] main
Entrypoint main = bundle.js
[./app.ts] 79 bytes {main} [built]
[./node_modules/a/index.ts] 517 bytes {main} [built] [failed] [1 error]
[./node_modules/a/index.ts] 568 bytes {main} [built] [failed] [1 error]

ERROR in ./node_modules/a/index.ts
Module build failed: Error: Typescript emitted no output for node_modules\a\index.ts.
You should not need to recompile .ts files in node_modules.
Please contact the package author to advise them to use --declaration --outDir.
More https://github.com/Microsoft/TypeScript/issues/12358
at successLoader (dist\index.js:39:15)
at Object.loader (dist\index.js:21:12)
Module build failed: Error: Typescript emitted no output for node_modules/a/index.ts. By default, ts-loader will not compile .ts files in node_modules.
You should not need to recompile .ts files there, but if you really want to, use the allowTsInNodeModules option.
See: https://github.com/Microsoft/TypeScript/issues/12358
at successLoader (dist/index.js:41:15)
at Object.loader (dist/index.js:21:12)
@ ./app.ts 3:8-20
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
/*! no static exports found */
/***/ (function(module, exports) {

eval("throw new Error(\"Module build failed: Error: ts-loader was supplied with an unexpected loader option: notRealOption/n/nPlease take a look at the options you are supplying; the following are valid options:/nsilent / logLevel / logInfoToStdOut / instance / compiler / context / configFile / transpileOnly / ignoreDiagnostics / errorFormatter / colors / compilerOptions / appendTsSuffixTo / appendTsxSuffixTo / onlyCompileBundledFiles / happyPackMode / getCustomTransformers / reportFiles / experimentalWatchApi/n/n at validateLoaderOptions (C://source//ts-loader//dist//index.js:103:19)/n at getLoaderOptions (C://source//ts-loader//dist//index.js:66:5)/n at Object.loader (C://source//ts-loader//dist//index.js:15:21)\");\n\n//# sourceURL=webpack:///./app.ts?");
eval("throw new Error(\"Module build failed: Error: ts-loader was supplied with an unexpected loader option: notRealOption/n/nPlease take a look at the options you are supplying; the following are valid options:/nsilent / logLevel / logInfoToStdOut / instance / compiler / context / configFile / transpileOnly / ignoreDiagnostics / errorFormatter / colors / compilerOptions / appendTsSuffixTo / appendTsxSuffixTo / onlyCompileBundledFiles / happyPackMode / getCustomTransformers / reportFiles / experimentalWatchApi / allowTsInNodeModules/n/n at validateLoaderOptions (/Users/alawson/dev/ts-loader/dist/index.js:110:19)/n at getLoaderOptions (/Users/alawson/dev/ts-loader/dist/index.js:72:5)/n at Object.loader (/Users/alawson/dev/ts-loader/dist/index.js:15:21)\");\n\n//# sourceURL=webpack:///./app.ts?");

/***/ })

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
Asset Size Chunks Chunk Names
bundle.js 3.51 KiB main [emitted] main
bundle.js 3.53 KiB main [emitted] main
Entrypoint main = bundle.js
[./app.ts] 728 bytes {main} [built] [failed] [1 error]
[./app.ts] 766 bytes {main} [built] [failed] [1 error]

ERROR in ./app.ts
Module build failed: Error: ts-loader was supplied with an unexpected loader option: notRealOption

Please take a look at the options you are supplying; the following are valid options:
silent / logLevel / logInfoToStdOut / instance / compiler / context / configFile / transpileOnly / ignoreDiagnostics / errorFormatter / colors / compilerOptions / appendTsSuffixTo / appendTsxSuffixTo / onlyCompileBundledFiles / happyPackMode / getCustomTransformers / reportFiles / experimentalWatchApi
silent / logLevel / logInfoToStdOut / instance / compiler / context / configFile / transpileOnly / ignoreDiagnostics / errorFormatter / colors / compilerOptions / appendTsSuffixTo / appendTsxSuffixTo / onlyCompileBundledFiles / happyPackMode / getCustomTransformers / reportFiles / experimentalWatchApi / allowTsInNodeModules

at validateLoaderOptions (dist\index.js:103:19)
at getLoaderOptions (dist\index.js:66:5)
at Object.loader (dist\index.js:15:21)
at validateLoaderOptions (dist/index.js:110:19)
at getLoaderOptions (dist/index.js:72:5)
at Object.loader (dist/index.js:15:21)
47 changes: 47 additions & 0 deletions test/execution-tests/allowTsInNodeModules/karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* eslint-disable no-var, strict */
'use strict';
var path = require('path');
var webpack = require('webpack');
var webpackConfig = require('./webpack.config.js');
var reporterOptions = require('../../reporterOptions');

module.exports = function(config) {
config.set({
browsers: [ 'ChromeHeadless' ],

files: [
// This loads all the tests
'main.js'
],

port: 9876,

frameworks: [ 'jasmine' ],

logLevel: config.LOG_INFO, //config.LOG_DEBUG

preprocessors: {
'main.js': [ 'webpack', 'sourcemap' ]
},

webpack: {
devtool: 'inline-source-map',
mode: webpackConfig.mode,
module: webpackConfig.module,
resolve: webpackConfig.resolve,

// for test harness purposes only, you would not need this in a normal project
resolveLoader: webpackConfig.resolveLoader
},

webpackMiddleware: {
quiet: true,
stats: {
colors: true
}
},

// reporter options
mochaReporter: reporterOptions
});
};
2 changes: 2 additions & 0 deletions test/execution-tests/allowTsInNodeModules/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const testsContext = require.context('./', true, /\.tests\.ts(x?)$/);
testsContext.keys().forEach(testsContext);
14 changes: 14 additions & 0 deletions test/execution-tests/allowTsInNodeModules/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "basic",
"license": "MIT",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"whitelistedModule": "file:../../testPackages/whitelistedModule",
"whitelistedFiles": "file:../../testPackages/whitelistedFiles"
},
"devDependencies": {
"@types/jasmine": "^2.5.35",
"jasmine-core": "^2.3.4"
}
}
5 changes: 5 additions & 0 deletions test/execution-tests/allowTsInNodeModules/src/whitelisted.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import whitelistedModule = require('whitelistedModule');

export function get() {
return whitelistedModule;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import whitelistedFile = require('whitelistedFiles/file');

export function get() {
return whitelistedFile;
}
13 changes: 13 additions & 0 deletions test/execution-tests/allowTsInNodeModules/test/app.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
describe("whitelisted", () => {
it("module can be imported", () => {
const whitelisted = require('../src/whitelisted');

expect(whitelisted.get()).toBe("my whitelisted module");
});

it("file can be imported", () => {
const whitelisted = require('../src/whitelisted_file');

expect(whitelisted.get()).toBe("a whitelisted file");
});
});
9 changes: 9 additions & 0 deletions test/execution-tests/allowTsInNodeModules/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": { },
"include": [
"./node_modules/whitelistedModule"
],
"files": [
"./node_modules/whitelistedFiles/file.ts"
]
}
23 changes: 23 additions & 0 deletions test/execution-tests/allowTsInNodeModules/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var path = require('path')

module.exports = {
mode: 'development',
entry: [
'./src/whitelisted.ts',
'./src/whitelisted_file.ts'
],
output: {
filename: 'bundle.js'
},
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-loader', options: { allowTsInNodeModules: true } }
]
}
}

// for test harness purposes only, you would not need this in a normal project
module.exports.resolveLoader = { alias: { 'ts-loader': path.join(__dirname, "../../../index.js") } }
17 changes: 17 additions & 0 deletions test/execution-tests/allowTsInNodeModules/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@types/jasmine@^2.5.35":
version "2.8.6"
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.6.tgz#14445b6a1613cf4e05dd61c3c3256d0e95c0421e"

jasmine-core@^2.3.4:
version "2.99.1"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.99.1.tgz#e6400df1e6b56e130b61c4bcd093daa7f6e8ca15"

"whitelistedFiles@file:../../testPackages/whitelistedFiles":
version "1.0.0"

"whitelistedModule@file:../../testPackages/whitelistedModule":
version "1.0.0"
3 changes: 3 additions & 0 deletions test/testPackages/whitelistedFiles/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var whitelistedFile = "a whitelisted file";

export = whitelistedFile;
5 changes: 5 additions & 0 deletions test/testPackages/whitelistedFiles/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "whitelistedFiles",
"version": "1.0.0",
"main": "file.ts"
}
3 changes: 3 additions & 0 deletions test/testPackages/whitelistedModule/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var whitelistedModule = "my whitelisted module";

export = whitelistedModule;
5 changes: 5 additions & 0 deletions test/testPackages/whitelistedModule/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "whitelistedModule",
"version": "1.0.0",
"main": "index.js"
}

0 comments on commit a150671

Please sign in to comment.