Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add allowTsInNodeModules option for importing .ts files from node_modules. #773

Merged
merged 10 commits into from
May 7, 2018
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"
}