-
-
Notifications
You must be signed in to change notification settings - Fork 433
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
ES2015 module issue with transpileOnly + decorators + interfaces #653
Comments
Ah, it's worse than I thought. Even after working around the warnings by moving interfaces to separate files, the actual generated code, is mashed, and the decorator references to even concrete types are broken. Correct output code in
Broken output code in
|
First of all: thanks for the detailed and minimal repro! That's always appreciated. I'm somewhat intrigued as to what's causing your issue since I'm using similar approaches in this project without anything choking. I'm not sure why that would be. TBH I'm somewhat time-poor right now and so I'm not likely to be able to look at this directly. That said, I'm happy to try and help you get to the bottom of it if I'm able to. I'd be tempted to advise doing the following:
See what, if anything that reveals... |
It may also be worth reading up on this issue: microsoft/TypeScript#18008 - I haven't read it thoroughly but it may be relevant. Also, does dropping |
Thanks. I'll take a look at your 'hours' repro and see what's going on there. Dropping Our entire codebase only has about 3 instances of this in there, so I've managed to work around the interface warnings by moving the interfaces to their own files. But the generated code is still borked. |
I've had a look at your 'hours' repo, and out of the box it doesn't choke, as you say, but I can get it to choke with two small changes:
That then produces:
This is a big issue for Angular 2+ which is reliant upon such metadata for its dependency injection. It looks like angular/cli is currently using a custom tsc wrapper for its TS compilation, and webpack for the rest of its build, but in our codebase we're using webpack all the way. microsoft/TypeScript#18008 does indeed look relevant, especially the comment in microsoft/TypeScript#18008 (comment). Interestingly they suggest that the different generated code (a runtime check) that I see with |
It could be worth reporting your experience on the TypeScript issue - they might be able to advise. I'd be interested if you've references to the relevant bit of the Angular cli... |
Yup, just logged a comment on the TS chain. It's proving a bit hard to find the angular wrapper, but there's a bit here: |
I am also experiencing this issue when I tried to use |
(I've not investigated further. Our team jumped ship to React as soon as FB changed the licence.) |
I use this plugin to remove warning. These warnings are useless, because TS already made a check for export exists. This plugin compatible with webpack 3 and 4 const ModuleDependencyWarning = require("webpack/lib/ModuleDependencyWarning")
module.exports = class IgnoreNotFoundExportPlugin {
apply(compiler) {
const messageRegExp = /export '.*'( \(reexported as '.*'\))? was not found in/
function doneHook(stats) {
stats.compilation.warnings = stats.compilation.warnings.filter(function(warn) {
if (warn instanceof ModuleDependencyWarning && messageRegExp.test(warn.message)) {
return false
}
return true;
})
}
if (compiler.hooks) {
compiler.hooks.done.tap("IgnoreNotFoundExportPlugin", doneHook)
} else {
compiler.plugin("done", doneHook)
}
}
} |
The workaround solution suggested by @Strate is very helpful. I'd be open to baking this into ts-loader since it seems to have bitten a few people... Would anyone like to submit a PR? |
BTW I'd only apply the change when |
It looks like there's 3 places in the codebase where errors are registered to webpack. See the top 3 files in this search https://github.com/TypeStrong/ts-loader/search?utf8=✓&q=errors.push&type= If in each call site we applied @Strate's |
I would also like to chime in here. We are using create-react-app with the react-scripts-ts that uses all webpack under the hood and Inverisfy JS for our IOC, and this is popping up all over the place. I'll try out the workaround. |
@Roustalski I'm having the same problem, but setting |
(Note that I mentioned earlier (#653 (comment)), that at that time it wasn't simply a case of ignoring the warnings. The generated code was broken. I don't know whether anything has changed since, but merely suppressing/filtering the warnings might not be sufficient...) |
Tuned @Strate’s plugin code to allow specifying what export warnings to ignore. I find this useful because such warnings have been helpful for me several times. Usage: // webpack.config.js
const IgnoreNotFoundExportPlugin = require('./IgnoreNotFoundExportPlugin.js');
module.exports = {
plugins: [
new IgnoreNotFoundExportPlugin(['MyInterface', 'MyAnotherInterface']),
// Would ignore export warnings that look like
// export 'MyInterface' was not found in './file'
// or
// export 'MyAnotherInterface' was not found in './file'
// but not others
]
} or // webpack.config.js
const IgnoreNotFoundExportPlugin = require('./IgnoreNotFoundExportPlugin.js');
module.exports = {
plugins: [
new IgnoreNotFoundExportPlugin(),
// Would ignore all “export not found” warnings
]
} Plugin code: See more// IgnoreNotFoundExportPlugin.js
const ModuleDependencyWarning = require('webpack/lib/ModuleDependencyWarning');
// ↓ Based on https://github.com/sindresorhus/escape-string-regexp
const escapeStringForRegExp = string => string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
module.exports = class IgnoreNotFoundExportPlugin {
constructor(exportsToIgnore) {
this.exportsToIgnore = exportsToIgnore || [];
}
getMessageRegExp() {
if (this.exportsToIgnore.length > 0) {
const exportsPattern =
'(' +
this.exportsToIgnore.map(escapeStringForRegExp).join('|') +
')';
return new RegExp(
`export '${
this.exportsToIgnore
}'( \\(reexported as '.*'\\))? was not found in`,
);
} else {
return /export '.*'( \(reexported as '.*'\))? was not found in/;
}
}
apply(compiler) {
const messageRegExp = this.getMessageRegExp();
const doneHook = stats => {
stats.compilation.warnings = stats.compilation.warnings.filter(
warn => {
if (
warn instanceof ModuleDependencyWarning &&
messageRegExp.test(warn.message)
) {
return false;
}
return true;
},
);
};
if (compiler.hooks) {
compiler.hooks.done.tap('IgnoreNotFoundExportPlugin', doneHook);
} else {
compiler.plugin('done', doneHook);
}
}
}; |
@iamakulov const from line 14 ( |
A modified version from @iamakulov 's code for my private project , supports passing regexp / string as ignore rules, to apply to file name or exported identifiers. Hope it can help a little: Usage (in webpack config): const IgnoreNotFoundPlugin = require('./IgnoreNotFoundExportPlugin.js');
plugins: [
new IgnoreNotFoundPlugin({
sourceFiles: [/\/files\/test$/, '../files/test2'] // Only ignore source file name matched with at least one of these regexp/string
exportNames: [ 'IInterface' ]
})
]
// Or
plugins: [
new IgnoreNotFoundPlugin() // All warnings will be ignored
] Plugin code: Click to expand
const ModuleDependencyWarning = require('webpack/lib/ModuleDependencyWarning');
module.exports = class IgnoreNotFoundExportPlugin {
constructor(option) {
const op = {
sourceFiles: [],
exportNames: [],
...option
};
this.ignoredSourceFiles = op.sourceFiles;
this.ignoredExportNames = op.exportNames;
}
apply(compiler) {
const reg = /export '(.*)' \((imported|reexported) as '.*'\)? was not found in '(.*)'/;
const doneHook = stats => {
stats.compilation.warnings = stats.compilation.warnings.filter(warn => {
if (!(warn instanceof ModuleDependencyWarning) || !warn.message) {
return true;
}
const matchedResult = warn.message.match(reg);
if (!matchedResult) {
return true;
}
const [, exportName, , sourceFile] = matchedResult;
const customRulesIgnore = {
exportNames: false,
sourceFiles: false
};
if (this.ignoredExportNames.length) {
for (let i = 0; i < this.ignoredExportNames.length; i++) {
const rule = this.ignoredExportNames[i];
if (typeof rule === 'string' && rule === exportName) {
customRulesIgnore.exportNames = true;
break;
} else if (rule instanceof RegExp && rule.test(exportName)) {
customRulesIgnore.exportNames = true;
break;
}
}
} else {
customRulesIgnore.exportNames = true;
}
if (this.ignoredSourceFiles.length) {
for (let i = 0; i < this.ignoredSourceFiles.length; i++) {
const rule = this.ignoredSourceFiles[i];
if (typeof rule === 'string' && rule === sourceFile) {
customRulesIgnore.sourceFiles = true;
break;
} else if (rule instanceof RegExp && rule.test(sourceFile)) {
customRulesIgnore.sourceFiles = true;
break;
}
}
} else {
customRulesIgnore.sourceFiles = true;
}
let ret = false;
Object.keys(customRulesIgnore).forEach(key => {
if (!customRulesIgnore[key]) {
ret = true;
}
});
return ret;
});
};
if (compiler.hooks) {
compiler.hooks.done.tap('IgnoreNotFoundExportPlugin', doneHook);
} else {
compiler.plugin('done', doneHook);
}
}
}; |
I have created a IgnoreNotFoundExportPlugin, which is configurable by import path, for example, to match only TypeScript files. I believe this solution to be more scalable for future import warning, without having to fix the config for every new warning. |
Tested the various solutions here, but somehow the following line always returns false:
Here's how the warn object looks like:
It clearly states that the warn is a ModuleDependencyWarning. Anyone has any idea what's going on? For reference, i'm using the following code:
|
I have the same issue:
with code:
But when I define type alias in the same file, I get rid off warning:
So it seems like a leaky beahavour. What makes local interface different from the imported one that raises warning? PS. |
I had the same problem that @weijian19391 mentioned. I used this condition instead:
in place of
|
If someone as the same issue with vue-cli, add module.exports = {
chainWebpack: config => {
config
.plugin("IgnoreNotFoundExportPlugin")
.before("friendly-errors")
.use(IgnoreNotFoundExportPlugin);
},
}; To vue.config.js The important part is "before("friendly-errors")" |
Using iamakulov's code, the plugin ran - but too late: the warnings were already outputed to the console. I had to use the // IgnoreNotFoundExportPlugin.js
const ModuleDependencyWarning = require('webpack/lib/ModuleDependencyWarning');
// ↓ Based on https://github.com/sindresorhus/escape-string-regexp
const escapeStringForRegExp = string => string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
module.exports = class IgnoreNotFoundExportPlugin {
constructor(exportsToIgnore) {
this.exportsToIgnore = exportsToIgnore || [];
}
getMessageRegExp() {
if (this.exportsToIgnore.length > 0) {
const exportsPattern =
'(' +
this.exportsToIgnore.map(escapeStringForRegExp).join('|') +
')';
return new RegExp(
`export '${
this.exportsToIgnore
}'( \\(reexported as '.*'\\))? was not found in`,
);
} else {
return /export '.*'( \(reexported as '.*'\))? was not found in/;
}
}
apply(compiler) {
const messageRegExp = this.getMessageRegExp();
const afterCompile = compilation => {
const stats = compilation.getStats();
stats.compilation.warnings = stats.compilation.warnings.filter(
warn => {
if (
warn instanceof ModuleDependencyWarning &&
messageRegExp.test(warn.message)
) {
return false;
}
return true;
},
);
};
if (compiler.hooks) {
compiler.hooks.afterCompile.tap('IgnoreNotFoundExportPlugin', afterCompile);
} else {
console.warn("webpack compiler-hooks not supported!");
// compiler.plugin('done', doneHook);
}
}
}; |
Both @iamakulov and @warappa 's scripts contain a bug in
|
Hi guys! I'm using @Strate's plugin on storybook since it doesn't support yet webpack property import { Compiler, Stats } from 'webpack';
// this kind of export in ts is not quite right but storybook `main` has some issues with export keyword
module.exports = class IgnoreNotFoundExportPlugin {
apply(compiler: Compiler) {
const messageRegExp = /export '.*'( \(reexported as '.*'\))? was not found in/;
const doneHook = (stats: Stats) =>
stats.compilation.warnings = stats.compilation.warnings.filter((warn: any) =>
// Unfortunately webpack is not exporting ModuleDependencyWarning type, so I'm using constructor.name instead
warn.constructor.name === 'ModuleDependencyWarning' && !messageRegExp.test(warn.message)
);
compiler.hooks.done.tap('IgnoreNotFoundExportPlugin', doneHook);
}
}; |
I got graphics.ts
in other file:
|
Will this ever be fixed? It's a common setup angular projects. |
Hey @GEMI , you know, this is open source and everyone helps in his/her free time. So, you are welcome to contribute a fix for this common setup 👍 See https://github.com/TypeStrong/ts-loader/blob/main/CONTRIBUTING.md for more information. |
hi,guys, thinks for your help; need to change |
Re-cloning the repository after deleting the project folder helped me to resolve the issue. |
Hi there,
We have a very large Angular 2 codebase that we're attempting to move over to
ts-loader
; we're getting massive (4-5x) speed boosts compared to our existing awesome-typescript-loader setup, but sadly we're getting compilation issues when we turn ontranspileOnly
.It only occurs when:
(webpack complains that it can't find the interface with a stack trace suggesting that it's processing harmony imports.)
I've created a repo with a standalone repro case in it: it's just tiny 2 files both of which are under 10 lines of code:
https://github.com/RoystonS/ts-loader-issue
(Is this related to what's discussed in issue #400?)
Thanks,
Royston.
The text was updated successfully, but these errors were encountered: