I have a monorepo usecase, where I want to share code between the next app and other modules that are located outside of the app folder.
It will end up with this error:
{ Error: (client) ../foo.ts 1:0
Module parse failed: The keyword 'interface' is reserved (1:0)
You may need an appropriate loader to handle this file type.
> interface Foo {
| prop: string;
| }
@ ./pages/index.tsx 4:0-28 8:5-8
@ multi ./pages/index.tsx
I have set up a simple repo here, based on the next-typescript example:
https://github.com/Swatinem/next-monorepo/tree/master
Whatever I import should be transpiled like everything else, period.
Related issue (possibly a duplicate?): https://github.com/zeit/next-plugins/issues/234
Also related maybe:
Sounds like this is a duplicate of https://github.com/zeit/next.js/issues/706
Just for reference, this is the extremely ugly workaround I found for this:
// NOTE(swatinem): we just assume the typescript loader is configured last
const tsxRules = config.module.rules[config.module.rules.length - 1]
// By default next-typescript only includes things in the app root for no real reason -_-
// See: https://github.com/zeit/next-plugins/blob/be21851f63e82845387e576f5f2ed3e5c448cb97/packages/next-typescript/index.js#L51
// See: https://github.com/zeit/next-plugins/issues/234
tsxRules.include = undefined
// Also, apparently babel does not search for the `.babelrc` based on the `root`
// option correctly when the file to transpile is outside of the root.
// See: https://babeljs.io/docs/en/options#root
// So we just pass a path to the babelrc manually here
defaultLoaders.babel.options.configFile = path.join(__dirname, '.babelrc')
Thanks @Swatinem! Made it slightly more resilient by searching for the relevant loader rather than relying on index:
config.module.rules.forEach((rule) => {
const ruleContainsTs = rule.test.toString().includes('ts|tsx');
if (ruleContainsTs && rule.use && rule.use.loader === 'next-babel-loader') {
rule.include = undefined;
}
});
@Swatinem, Thanx for the workaround I've spent few hours till found this thread.
For easier debug, you can console.log
the config
and find out the exact ts-loader, then modify it.
Going to track this in #706
Apparently someone changed the regex in the rules to /\.(tsx|ts|js|mjs|jsx)$/
, thus the fix suggested by @jakemmarsh only works if you check for .includes("tsx|ts")
...
I feel like this should be re-opened because it's a different issue. This one is for files outside of the nextjs root, and #706 is for files within the nextjs root, but in the node_modules
folder.
I seems that transpileModules works for me.
module.exports = withBundleAnalyzer(
withTranspileModules({
// To force Next.js to transpile code from other workspace packages.
// https://github.com/martpie/next-transpile-modules
transpileModules: ['evolu'],
// We need server for local next export for integration tests.
// We can detects ZEIT Now runtime via AWS_REGION.
target: process.env.AWS_REGION ? 'serverless' : 'server',
// Enforce relative paths for integration tests.
// https://github.com/zeit/next.js/issues/2581
assetPrefix: './',
}),
);
You can also specify a path to an external folder.
config.module.rules.forEach((rule) => {
const isTsRule = rule.test && rule.test.toString().includes('tsx|ts');
if (isTsRule && rule.use && rule.use.loader === 'next-babel-loader') {
rule.include = [
path.join(__dirname, 'path', 'to', 'external', 'folder'),
...rule.include
];
}
});
@jakemmarsh This works for me:
const ruleString = rule.test ? rule.test.toString() : ''
const ruleContainsTs = /tsx?/.test(ruleString)
if (ruleContainsTs && rule.use && rule.use.loader === 'next-babel-loader') {
rule.include = undefined
}
Does Next dev mode rebuilds on change of the external files?
We made this library to do this - it's not 100% reliable but it's pretty good.
Most helpful comment
Thanks @Swatinem! Made it slightly more resilient by searching for the relevant loader rather than relying on index: