-
Please refer to this commit: yf-yang@6d73dcc I create a typescript alias In the nextjs app, the module resolver get confused of the alias Before, I was using ts-patch to deal with the conversion when compiling each dependencies into JavaScript, but if I want to directly refer those dependencies in the nextjs app like the repo shows, is there any solution? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
I found this gist but still have no idea (sorry I am not familiar with webpack, not sure if this is a typescript or webpack problem) https://gist.github.com/nerdyman/2f97b24ab826623bff9202750013f99e |
Beta Was this translation helpful? Give feedback.
-
Got it work, I wrote a webpack plugin similar to https://github.com/dividab/tsconfig-paths-webpack-plugin/blob/master/src/plugin.ts To enable: // next.config.mjs
import { MonorepoResolvePlugin } from './monorepo-resolve-plugin.mjs';
const nextConfig = {
webpack: (config) => {
// ...other codes
config.resolve = {
...config.resolve,
plugins: [
...config.resolve.plugins,
new MonorepoResolvePlugin({
appRoot: process.cwd(),
workspaceParents: [
'../../apps',
'/workspaces/nextjs-monorepo-example/packages/',
],
}),
],
};
}
}; // monorepo-resolve-plugin.mjs
import path from 'path';
import createInnerContext from 'enhanced-resolve/lib/createInnerContext.js';
import getInnerRequest from 'enhanced-resolve/lib/getInnerRequest.js';
import * as tsconfigPaths from 'tsconfig-paths';
function subdirOf(parent, dir) {
const relative = path.relative(parent, dir);
return !relative.startsWith('..') && !path.isAbsolute(relative) && relative;
}
export class MonorepoResolvePlugin {
constructor({ appRoot, workspaceParents = [] }) {
this.appRoot = appRoot;
this.workspaceParents = workspaceParents;
this.cache = {};
}
apply(resolver) {
const target = resolver.ensureHook('internal-resolve');
const readJson = createReadJsonAsync(resolver.fileSystem);
const fileExist = createFileExistAsync(resolver.fileSystem);
resolver
.getHook('raw-resolve')
.tapAsync(
'MonorepoResolvePlugin',
(request, resolveContext, callback) => {
const innerRequest = getInnerRequest(resolver, request);
if (
!innerRequest ||
request?.request?.startsWith('.') ||
request?.request?.startsWith('..')
) {
return callback();
}
// current appRoot's alias is handled by webpack
if (subdirOf(this.appRoot, request.path) !== false) {
return callback();
}
let cacheEntry = undefined;
for (const [parent, entry] of Object.entries(this.cache)) {
if (subdirOf(parent, request.path) !== false) {
cacheEntry = entry;
break;
}
}
if (cacheEntry === undefined) {
findTsConfig: for (const workspaceParent of this.workspaceParents) {
const subdir = subdirOf(workspaceParent, request.path);
if (!subdir) {
continue;
}
const subdirParts = subdir.split('/');
subdirParts.unshift('');
let maybeWorkspaceRoot = workspaceParent;
while (subdirParts.length) {
maybeWorkspaceRoot = path.join(
maybeWorkspaceRoot,
subdirParts.shift()
);
const loadResult = tsconfigPaths.loadConfig(maybeWorkspaceRoot);
if (loadResult.resultType === 'success') {
cacheEntry = {
absoluteBaseUrl: loadResult.absoluteBaseUrl,
matchPath: tsconfigPaths.createMatchPathAsync(
loadResult.absoluteBaseUrl,
loadResult.paths
),
};
this.cache[maybeWorkspaceRoot] = cacheEntry;
break findTsConfig;
}
}
}
}
if (cacheEntry === undefined) {
return callback();
}
const { absoluteBaseUrl, matchPath } = cacheEntry;
// reference: https://github.com/dividab/tsconfig-paths-webpack-plugin/blob/master/src/plugin.ts
matchPath(
innerRequest,
readJson,
fileExist,
['.ts', '.tsx'],
(err, foundMatch) => {
if (err) {
return callback(err);
}
if (!foundMatch) {
return callback();
}
const newRequest = {
...request,
request: foundMatch,
path: absoluteBaseUrl,
};
return resolver.doResolve(
target,
newRequest,
`Resolved request '${innerRequest}' to '${foundMatch}' using tsconfig.json paths mapping`,
createInnerContext({ resolveContext }),
(err2, result2) => {
// Pattern taken from:
// https://github.com/webpack/enhanced-resolve/blob/42ff594140582c3f8f86811f95dea7bf6774a1c8/lib/AliasPlugin.js#L44
if (err2) {
return callback(err2);
}
// Don't allow other aliasing or raw request
if (result2 === undefined) {
return callback(undefined, undefined);
}
callback(undefined, result2);
}
);
}
);
}
);
}
}
function createReadJsonAsync(fileSystem) {
return (path2, callback2) => {
fileSystem.readJson(path2, (err, json) => {
// If error assume file does not exist
if (err || !json) {
callback2();
return;
}
callback2(undefined, json);
});
};
}
function createFileExistAsync(fileSystem) {
return (path2, callback2) => {
fileSystem.stat(path2, (err, stats) => {
// If error assume file does not exist
if (err) {
callback2(undefined, false);
return;
}
callback2(undefined, stats ? stats.isFile() : false);
});
};
} |
Beta Was this translation helpful? Give feedback.
Got it work, I wrote a webpack plugin similar to https://github.com/dividab/tsconfig-paths-webpack-plugin/blob/master/src/plugin.ts
To enable: