fix(core): stop inlining tsconfig-paths-webpack-plugin and use version with fix (#8357)
This commit is contained in:
parent
78c9f158a7
commit
be91d1f99a
@ -235,7 +235,7 @@
|
|||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"ts-node": "9.1.1",
|
"ts-node": "9.1.1",
|
||||||
"tsconfig-paths": "^3.9.0",
|
"tsconfig-paths": "^3.9.0",
|
||||||
"tsconfig-paths-webpack-plugin": "3.4.1",
|
"tsconfig-paths-webpack-plugin": "3.5.2",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"tslint": "6.1.3",
|
"tslint": "6.1.3",
|
||||||
"tslint-to-eslint-config": "^2.4.0",
|
"tslint-to-eslint-config": "^2.4.0",
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
"enhanced-resolve": "^5.8.3",
|
"enhanced-resolve": "^5.8.3",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"tsconfig-paths": "^3.9.0",
|
"tsconfig-paths": "^3.9.0",
|
||||||
"tsconfig-paths-webpack-plugin": "3.4.1",
|
"tsconfig-paths-webpack-plugin": "3.5.2",
|
||||||
"webpack-node-externals": "^3.0.0",
|
"webpack-node-externals": "^3.0.0",
|
||||||
"fork-ts-checker-webpack-plugin": "6.2.10",
|
"fork-ts-checker-webpack-plugin": "6.2.10",
|
||||||
"rxjs": "^6.5.4",
|
"rxjs": "^6.5.4",
|
||||||
|
|||||||
@ -2,16 +2,11 @@ import { createWebpackConfig, prepareConfig } from './config';
|
|||||||
import { NextBuildBuilderOptions } from '@nrwl/next';
|
import { NextBuildBuilderOptions } from '@nrwl/next';
|
||||||
import { dirname } from 'path';
|
import { dirname } from 'path';
|
||||||
import { importConstants } from './require-shim';
|
import { importConstants } from './require-shim';
|
||||||
// Inlining tsconfig-paths-webpack-plugin with a patch
|
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||||
// See: https://github.com/dividab/tsconfig-paths-webpack-plugin/pull/85
|
|
||||||
// TODO(jack): Remove once the patch lands in original package
|
|
||||||
import { TsconfigPathsPlugin } from '@nrwl/web/src/utils/webpack/plugins/tsconfig-paths/tsconfig-paths.plugin';
|
|
||||||
|
|
||||||
const { PHASE_PRODUCTION_BUILD } = importConstants();
|
const { PHASE_PRODUCTION_BUILD } = importConstants();
|
||||||
|
|
||||||
jest.mock(
|
jest.mock('tsconfig-paths-webpack-plugin');
|
||||||
'@nrwl/web/src/utils/webpack/plugins/tsconfig-paths/tsconfig-paths.plugin'
|
|
||||||
);
|
|
||||||
jest.mock('next/dist/server/config', () => ({
|
jest.mock('next/dist/server/config', () => ({
|
||||||
__esModule: true,
|
__esModule: true,
|
||||||
default: () => ({
|
default: () => ({
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import type {
|
|||||||
PHASE_PRODUCTION_SERVER,
|
PHASE_PRODUCTION_SERVER,
|
||||||
} from 'next/dist/shared/lib/constants';
|
} from 'next/dist/shared/lib/constants';
|
||||||
import { join, resolve } from 'path';
|
import { join, resolve } from 'path';
|
||||||
import { TsconfigPathsPlugin } from '@nrwl/web/src/utils/webpack/plugins/tsconfig-paths/tsconfig-paths.plugin';
|
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||||
import { Configuration } from 'webpack';
|
import { Configuration } from 'webpack';
|
||||||
import {
|
import {
|
||||||
FileReplacement,
|
FileReplacement,
|
||||||
@ -71,7 +71,7 @@ export function createWebpackConfig(
|
|||||||
configFile: tsConfigPath,
|
configFile: tsConfigPath,
|
||||||
extensions,
|
extensions,
|
||||||
mainFields,
|
mainFields,
|
||||||
}),
|
}) as never, // TODO: Remove never type when 'tsconfig-paths-webpack-plugin' types fixed
|
||||||
];
|
];
|
||||||
|
|
||||||
fileReplacements
|
fileReplacements
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
"tree-kill": "1.2.2",
|
"tree-kill": "1.2.2",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"tsconfig-paths": "^3.9.0",
|
"tsconfig-paths": "^3.9.0",
|
||||||
"tsconfig-paths-webpack-plugin": "3.4.1",
|
"tsconfig-paths-webpack-plugin": "3.5.2",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"webpack": "^5.58.1",
|
"webpack": "^5.58.1",
|
||||||
"webpack-merge": "^5.8.0",
|
"webpack-merge": "^5.8.0",
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import type { ProjectGraph } from '@nrwl/workspace/src/core/project-graph';
|
|||||||
import buildExecutor from './build.impl';
|
import buildExecutor from './build.impl';
|
||||||
import { BuildNodeBuilderOptions } from '../../utils/types';
|
import { BuildNodeBuilderOptions } from '../../utils/types';
|
||||||
|
|
||||||
jest.mock('../../utils/webpack/plugins/tsconfig-paths/tsconfig-paths.plugin');
|
jest.mock('tsconfig-paths-webpack-plugin');
|
||||||
jest.mock('../../utils/run-webpack', () => ({
|
jest.mock('../../utils/run-webpack', () => ({
|
||||||
runWebpack: jest.fn(),
|
runWebpack: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -8,11 +8,7 @@ import { BuildBuilderOptions } from './types';
|
|||||||
import { loadTsPlugins } from './load-ts-plugins';
|
import { loadTsPlugins } from './load-ts-plugins';
|
||||||
import CopyWebpackPlugin = require('copy-webpack-plugin');
|
import CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||||
|
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||||
// Inlining tsconfig-paths-webpack-plugin with a patch
|
|
||||||
// See: https://github.com/dividab/tsconfig-paths-webpack-plugin/pull/85
|
|
||||||
// TODO(jack): Remove once the patch lands in original package
|
|
||||||
import TsConfigPathsPlugin from './webpack/plugins/tsconfig-paths/tsconfig-paths.plugin';
|
|
||||||
|
|
||||||
export const OUT_FILENAME_TEMPLATE = '[name].js';
|
export const OUT_FILENAME_TEMPLATE = '[name].js';
|
||||||
|
|
||||||
@ -85,11 +81,11 @@ export function getBaseWebpackPartial(
|
|||||||
extensions,
|
extensions,
|
||||||
alias: getAliases(options),
|
alias: getAliases(options),
|
||||||
plugins: [
|
plugins: [
|
||||||
new TsConfigPathsPlugin({
|
new TsconfigPathsPlugin({
|
||||||
configFile: options.tsConfig,
|
configFile: options.tsConfig,
|
||||||
extensions,
|
extensions,
|
||||||
mainFields,
|
mainFields,
|
||||||
}),
|
}) as never, // TODO: Remove never type when 'tsconfig-paths-webpack-plugin' types fixed
|
||||||
],
|
],
|
||||||
mainFields,
|
mainFields,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { getNodeWebpackConfig } from './node.config';
|
import { getNodeWebpackConfig } from './node.config';
|
||||||
import TsConfigPathsPlugin from './webpack/plugins/tsconfig-paths/tsconfig-paths.plugin';
|
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||||
import { BuildNodeBuilderOptions } from './types';
|
import { BuildNodeBuilderOptions } from './types';
|
||||||
|
|
||||||
jest.mock('./webpack/plugins/tsconfig-paths/tsconfig-paths.plugin');
|
jest.mock('tsconfig-paths-webpack-plugin');
|
||||||
jest.mock('@nrwl/tao/src/utils/app-root', () => ({
|
jest.mock('@nrwl/tao/src/utils/app-root', () => ({
|
||||||
get appRootPath() {
|
get appRootPath() {
|
||||||
return join(__dirname, '../../../..');
|
return join(__dirname, '../../../..');
|
||||||
@ -21,7 +21,7 @@ describe('getNodePartial', () => {
|
|||||||
fileReplacements: [],
|
fileReplacements: [],
|
||||||
statsJson: false,
|
statsJson: false,
|
||||||
};
|
};
|
||||||
(<any>TsConfigPathsPlugin).mockImplementation(
|
(<any>TsconfigPathsPlugin).mockImplementation(
|
||||||
function MockPathsPlugin() {}
|
function MockPathsPlugin() {}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,83 +0,0 @@
|
|||||||
import { Console } from 'console';
|
|
||||||
import { Chalk } from 'chalk';
|
|
||||||
import { Options } from './tsconfig-paths.options';
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
type InternalLoggerFunc = (whereToLog: any, message: string) => void;
|
|
||||||
|
|
||||||
export type LoggerFunc = (message: string) => void;
|
|
||||||
|
|
||||||
export interface Logger {
|
|
||||||
log: LoggerFunc;
|
|
||||||
logInfo: LoggerFunc;
|
|
||||||
logWarning: LoggerFunc;
|
|
||||||
logError: LoggerFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LogLevel {
|
|
||||||
INFO = 1,
|
|
||||||
WARN = 2,
|
|
||||||
ERROR = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
const stderrConsole = new Console(process.stderr);
|
|
||||||
const stdoutConsole = new Console(process.stdout);
|
|
||||||
|
|
||||||
const doNothingLogger = (_message: string) => {
|
|
||||||
/* Do nothing */
|
|
||||||
};
|
|
||||||
|
|
||||||
const makeLoggerFunc = (options: Options): InternalLoggerFunc =>
|
|
||||||
options.silent
|
|
||||||
? (_whereToLog: Console, _message: string) => {
|
|
||||||
/* Do nothing */
|
|
||||||
}
|
|
||||||
: (whereToLog: Console, message: string) => whereToLog.log(message);
|
|
||||||
|
|
||||||
const makeExternalLogger =
|
|
||||||
(loaderOptions: Options, logger: InternalLoggerFunc) => (message: string) =>
|
|
||||||
logger(
|
|
||||||
loaderOptions.logInfoToStdOut ? stdoutConsole : stderrConsole,
|
|
||||||
message
|
|
||||||
);
|
|
||||||
|
|
||||||
const makeLogInfo = (
|
|
||||||
options: Options,
|
|
||||||
logger: InternalLoggerFunc,
|
|
||||||
green: Chalk
|
|
||||||
) =>
|
|
||||||
LogLevel[options.logLevel] <= LogLevel.INFO
|
|
||||||
? (message: string) =>
|
|
||||||
logger(
|
|
||||||
options.logInfoToStdOut ? stdoutConsole : stderrConsole,
|
|
||||||
green(message)
|
|
||||||
)
|
|
||||||
: doNothingLogger;
|
|
||||||
|
|
||||||
const makeLogError = (
|
|
||||||
options: Options,
|
|
||||||
logger: InternalLoggerFunc,
|
|
||||||
red: Chalk
|
|
||||||
) =>
|
|
||||||
LogLevel[options.logLevel] <= LogLevel.ERROR
|
|
||||||
? (message: string) => logger(stderrConsole, red(message))
|
|
||||||
: doNothingLogger;
|
|
||||||
|
|
||||||
const makeLogWarning = (
|
|
||||||
options: Options,
|
|
||||||
logger: InternalLoggerFunc,
|
|
||||||
yellow: Chalk
|
|
||||||
) =>
|
|
||||||
LogLevel[options.logLevel] <= LogLevel.WARN
|
|
||||||
? (message: string) => logger(stderrConsole, yellow(message))
|
|
||||||
: doNothingLogger;
|
|
||||||
|
|
||||||
export function makeLogger(options: Options, colors: Chalk): Logger {
|
|
||||||
const logger = makeLoggerFunc(options);
|
|
||||||
return {
|
|
||||||
log: makeExternalLogger(options, logger),
|
|
||||||
logInfo: makeLogInfo(options, logger, colors.green),
|
|
||||||
logWarning: makeLogWarning(options, logger, colors.yellow),
|
|
||||||
logError: makeLogError(options, logger, colors.red),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
export type LogLevel = 'INFO' | 'WARN' | 'ERROR';
|
|
||||||
|
|
||||||
export interface Options {
|
|
||||||
readonly configFile: string;
|
|
||||||
readonly extensions: ReadonlyArray<string>;
|
|
||||||
readonly baseUrl: string | undefined;
|
|
||||||
readonly silent: boolean;
|
|
||||||
readonly logLevel: LogLevel;
|
|
||||||
readonly logInfoToStdOut: boolean;
|
|
||||||
readonly context: string | undefined;
|
|
||||||
readonly colors: boolean;
|
|
||||||
readonly mainFields: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
type ValidOptions = keyof Options;
|
|
||||||
const validOptions: ReadonlyArray<ValidOptions> = [
|
|
||||||
'configFile',
|
|
||||||
'extensions',
|
|
||||||
'baseUrl',
|
|
||||||
'silent',
|
|
||||||
'logLevel',
|
|
||||||
'logInfoToStdOut',
|
|
||||||
'context',
|
|
||||||
'mainFields',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes raw options from the webpack config,
|
|
||||||
* validates them and adds defaults for missing options
|
|
||||||
*/
|
|
||||||
export function getOptions(rawOptions: {}): Options {
|
|
||||||
validateOptions(rawOptions);
|
|
||||||
|
|
||||||
const options = makeOptions(rawOptions);
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the supplied loader options.
|
|
||||||
* At present this validates the option names only; in future we may look at validating the values too
|
|
||||||
* @param rawOptions
|
|
||||||
*/
|
|
||||||
function validateOptions(rawOptions: {}): void {
|
|
||||||
const loaderOptionKeys = Object.keys(rawOptions);
|
|
||||||
for (let i = 0; i < loaderOptionKeys.length; i++) {
|
|
||||||
const option = loaderOptionKeys[i];
|
|
||||||
const isUnexpectedOption =
|
|
||||||
(validOptions as ReadonlyArray<string>).indexOf(option) === -1;
|
|
||||||
if (isUnexpectedOption) {
|
|
||||||
throw new Error(`tsconfig-paths-webpack-plugin was supplied with an unexpected loader option: ${option}
|
|
||||||
Please take a look at the options you are supplying; the following are valid options:
|
|
||||||
${validOptions.join(' / ')}
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeOptions(rawOptions: Partial<Options>): Options {
|
|
||||||
const options: Options = {
|
|
||||||
...({
|
|
||||||
configFile: 'tsconfig.json',
|
|
||||||
extensions: ['.ts', '.tsx'],
|
|
||||||
baseUrl: undefined,
|
|
||||||
silent: false,
|
|
||||||
logLevel: 'WARN',
|
|
||||||
logInfoToStdOut: false,
|
|
||||||
context: undefined,
|
|
||||||
colors: true,
|
|
||||||
mainFields: ['main'],
|
|
||||||
} as Options),
|
|
||||||
...rawOptions,
|
|
||||||
};
|
|
||||||
|
|
||||||
const options2: Options = {
|
|
||||||
...options,
|
|
||||||
logLevel: options.logLevel.toUpperCase() as LogLevel,
|
|
||||||
};
|
|
||||||
|
|
||||||
return options2;
|
|
||||||
}
|
|
||||||
@ -1,353 +0,0 @@
|
|||||||
// Adapted from https://github.com/dividab/tsconfig-paths-webpack-plugin
|
|
||||||
import * as chalk from 'chalk';
|
|
||||||
import * as TsconfigPaths from 'tsconfig-paths';
|
|
||||||
import * as path from 'path';
|
|
||||||
import * as Options from './tsconfig-paths.options';
|
|
||||||
import * as Logger from './tsconfig-paths.logger';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import { ResolveContext, ResolveRequest } from 'enhanced-resolve';
|
|
||||||
type ResolvePluginInstance = any;
|
|
||||||
type Resolver = any;
|
|
||||||
|
|
||||||
type FileSystem = Resolver['fileSystem'];
|
|
||||||
type TapAsyncCallback = (
|
|
||||||
request: ResolveRequest,
|
|
||||||
context: ResolveContext,
|
|
||||||
callback: TapAsyncInnerCallback
|
|
||||||
) => void;
|
|
||||||
type TapAsyncInnerCallback = (
|
|
||||||
error?: Error | null | false,
|
|
||||||
result?: null | ResolveRequest
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
export interface LegacyResolverPlugin {
|
|
||||||
readonly apply: (resolver: LegacyResolver) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LegacyResolver {
|
|
||||||
readonly apply: (plugin: LegacyResolverPlugin) => void;
|
|
||||||
readonly plugin: (source: string, cb: ResolverCallbackLegacy) => void;
|
|
||||||
readonly doResolve: doResolveLegacy | doResolve;
|
|
||||||
readonly join: (relativePath: string, innerRequest: Request) => Request;
|
|
||||||
readonly fileSystem: LegacyResolverFileSystem;
|
|
||||||
readonly getHook: (hook: string) => Tapable;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type doResolveLegacy = (
|
|
||||||
target: string,
|
|
||||||
req: Request,
|
|
||||||
desc: string,
|
|
||||||
callback: Callback
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
export type doResolve = (
|
|
||||||
hook: Tapable,
|
|
||||||
req: Request,
|
|
||||||
message: string,
|
|
||||||
resolveContext: LegacyResolveContext,
|
|
||||||
callback: Callback
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
export type ReadJsonCallback = (error: Error | undefined, result?: {}) => void;
|
|
||||||
|
|
||||||
export type ReadJson = (path2: string, callback: ReadJsonCallback) => void;
|
|
||||||
|
|
||||||
export type LegacyResolverFileSystem = typeof fs & { readJson?: ReadJson };
|
|
||||||
|
|
||||||
export interface LegacyResolveContext {
|
|
||||||
log?: string;
|
|
||||||
stack?: string;
|
|
||||||
missing?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Tapable {
|
|
||||||
readonly tapAsync: (
|
|
||||||
options: TapableOptions,
|
|
||||||
callback: TapAsyncCallback
|
|
||||||
) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TapableOptions {
|
|
||||||
readonly name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ResolverCallbackLegacy = (
|
|
||||||
request: Request,
|
|
||||||
callback: Callback
|
|
||||||
) => void;
|
|
||||||
export type ResolverCallback = (
|
|
||||||
request: Request,
|
|
||||||
resolveContext: LegacyResolveContext,
|
|
||||||
callback: Callback
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
type CreateInnerCallback = (
|
|
||||||
callback: Callback,
|
|
||||||
options: Callback,
|
|
||||||
message?: string,
|
|
||||||
messageOptional?: string
|
|
||||||
) => Callback;
|
|
||||||
|
|
||||||
type CreateInnerContext = (
|
|
||||||
options: {
|
|
||||||
log?: string;
|
|
||||||
stack?: string;
|
|
||||||
missing?: string;
|
|
||||||
},
|
|
||||||
message?: string,
|
|
||||||
messageOptional?: string
|
|
||||||
) => ResolveContext;
|
|
||||||
|
|
||||||
type getInnerRequest = (
|
|
||||||
resolver: Resolver | LegacyResolver,
|
|
||||||
request: ResolveRequest | Request
|
|
||||||
) => string;
|
|
||||||
|
|
||||||
export interface Request {
|
|
||||||
readonly request?: Request | string;
|
|
||||||
readonly relativePath: string;
|
|
||||||
readonly path: string;
|
|
||||||
readonly context: {
|
|
||||||
readonly issuer: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Callback {
|
|
||||||
(err?: Error, result?: string): void;
|
|
||||||
|
|
||||||
log?: string;
|
|
||||||
stack?: string;
|
|
||||||
missing?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getInnerRequest: getInnerRequest = require('enhanced-resolve/lib/getInnerRequest');
|
|
||||||
|
|
||||||
export class TsconfigPathsPlugin implements ResolvePluginInstance {
|
|
||||||
source: string = 'described-resolve';
|
|
||||||
target: string = 'resolve';
|
|
||||||
|
|
||||||
log: Logger.Logger;
|
|
||||||
baseUrl: string;
|
|
||||||
absoluteBaseUrl: string;
|
|
||||||
extensions: ReadonlyArray<string>;
|
|
||||||
|
|
||||||
matchPath: TsconfigPaths.MatchPathAsync;
|
|
||||||
|
|
||||||
constructor(rawOptions: Partial<Options.Options> = {}) {
|
|
||||||
const options = Options.getOptions(rawOptions);
|
|
||||||
|
|
||||||
this.extensions = options.extensions;
|
|
||||||
|
|
||||||
// const colors = new chalk.constructor({ enabled: options.colors });
|
|
||||||
|
|
||||||
this.log = Logger.makeLogger(
|
|
||||||
options,
|
|
||||||
new chalk.Instance({ level: options.colors ? undefined : 0 })
|
|
||||||
);
|
|
||||||
|
|
||||||
const context = options.context || process.cwd();
|
|
||||||
const loadFrom = options.configFile || context;
|
|
||||||
|
|
||||||
const loadResult = TsconfigPaths.loadConfig(loadFrom);
|
|
||||||
if (loadResult.resultType === 'failed') {
|
|
||||||
this.log.logError(`Failed to load ${loadFrom}: ${loadResult.message}`);
|
|
||||||
} else {
|
|
||||||
this.log.logInfo(
|
|
||||||
`tsconfig-paths-webpack-plugin: Using config file at ${loadResult.configFileAbsolutePath}`
|
|
||||||
);
|
|
||||||
this.baseUrl = options.baseUrl || loadResult.baseUrl;
|
|
||||||
this.absoluteBaseUrl = options.baseUrl
|
|
||||||
? path.resolve(options.baseUrl)
|
|
||||||
: loadResult.absoluteBaseUrl;
|
|
||||||
this.matchPath = TsconfigPaths.createMatchPathAsync(
|
|
||||||
this.absoluteBaseUrl,
|
|
||||||
loadResult.paths,
|
|
||||||
options.mainFields
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(resolver: Resolver): void {
|
|
||||||
if (!resolver) {
|
|
||||||
this.log.logWarning(
|
|
||||||
'tsconfig-paths-webpack-plugin: Found no resolver, not applying tsconfig-paths-webpack-plugin'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { baseUrl } = this;
|
|
||||||
|
|
||||||
if (!baseUrl) {
|
|
||||||
// Nothing to do if there is no baseUrl
|
|
||||||
this.log.logWarning(
|
|
||||||
'tsconfig-paths-webpack-plugin: Found no baseUrl in tsconfig.json, not applying tsconfig-paths-webpack-plugin'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The file system only exists when the plugin is in the resolve context. This means it's also properly placed in the resolve.plugins array.
|
|
||||||
// If not, we should warn the user that this plugin should be placed in resolve.plugins and not the plugins array of the root config for example.
|
|
||||||
// This should hopefully prevent issues like: https://github.com/dividab/tsconfig-paths-webpack-plugin/issues/9
|
|
||||||
if (!('fileSystem' in resolver)) {
|
|
||||||
this.log.logWarning(
|
|
||||||
'tsconfig-paths-webpack-plugin: No file system found on resolver.' +
|
|
||||||
" Please make sure you've placed the plugin in the correct part of the configuration." +
|
|
||||||
' This plugin is a resolver plugin and should be placed in the resolve part of the Webpack configuration.'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolver.getHook(this.source).tapAsync(
|
|
||||||
{ name: 'TsconfigPathsPlugin' },
|
|
||||||
// @ts-ignore
|
|
||||||
createPluginCallback(
|
|
||||||
this.matchPath,
|
|
||||||
resolver,
|
|
||||||
this.absoluteBaseUrl,
|
|
||||||
// @ts-ignore
|
|
||||||
resolver.getHook(this.target),
|
|
||||||
this.extensions
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createPluginCallback(
|
|
||||||
matchPath: TsconfigPaths.MatchPathAsync,
|
|
||||||
resolver: Resolver,
|
|
||||||
absoluteBaseUrl: string,
|
|
||||||
hook: Tapable,
|
|
||||||
extensions: ReadonlyArray<string>
|
|
||||||
): TapAsyncCallback {
|
|
||||||
const fileExistAsync = createFileExistAsync(resolver.fileSystem);
|
|
||||||
const readJsonAsync = createReadJsonAsync(resolver.fileSystem);
|
|
||||||
return (
|
|
||||||
request: ResolveRequest,
|
|
||||||
resolveContext: ResolveContext,
|
|
||||||
callback: TapAsyncInnerCallback
|
|
||||||
) => {
|
|
||||||
const innerRequest = getInnerRequest(resolver, request);
|
|
||||||
|
|
||||||
// innerRequest never starts with '.' in new enhanced-resolve
|
|
||||||
if (
|
|
||||||
!innerRequest ||
|
|
||||||
request?.request?.startsWith('.') ||
|
|
||||||
request?.request?.startsWith('..')
|
|
||||||
) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
matchPath(
|
|
||||||
innerRequest,
|
|
||||||
readJsonAsync,
|
|
||||||
fileExistAsync,
|
|
||||||
extensions,
|
|
||||||
(err, foundMatch) => {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundMatch) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
const newRequest = {
|
|
||||||
...request,
|
|
||||||
request: foundMatch,
|
|
||||||
path: absoluteBaseUrl,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only at this point we are sure we are dealing with the latest Webpack version (>= 4.0.0)
|
|
||||||
// So only now can we require the createInnerContext function.
|
|
||||||
// (It doesn't exist in legacy versions)
|
|
||||||
const createInnerContext: CreateInnerContext = require('enhanced-resolve/lib/createInnerContext');
|
|
||||||
|
|
||||||
return resolver.doResolve(
|
|
||||||
hook,
|
|
||||||
newRequest as never,
|
|
||||||
`Resolved request '${innerRequest}' to '${foundMatch}' using tsconfig.json paths mapping`,
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
createInnerContext({ ...(resolveContext as any) }),
|
|
||||||
(err2: Error, result2: ResolveRequest): void => {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
callback(undefined, result2);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readJson(
|
|
||||||
fileSystem: FileSystem,
|
|
||||||
path2: string,
|
|
||||||
callback: ReadJsonCallback
|
|
||||||
): void {
|
|
||||||
if ('readJson' in fileSystem && fileSystem.readJson) {
|
|
||||||
return fileSystem.readJson(path2, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileSystem.readFile(path2, (err, buf) => {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
let data;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// @ts-ignore This will crash if buf is undefined, which I guess it can be...
|
|
||||||
data = JSON.parse(buf.toString('utf-8'));
|
|
||||||
} catch (e) {
|
|
||||||
return callback(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback(undefined, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createReadJsonAsync(
|
|
||||||
filesystem: FileSystem
|
|
||||||
): TsconfigPaths.ReadJsonAsync {
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
return (path2: string, callback2: (err?: Error, content?: any) => void) => {
|
|
||||||
readJson(filesystem, path2, (err, json) => {
|
|
||||||
// If error assume file does not exist
|
|
||||||
if (err || !json) {
|
|
||||||
callback2();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback2(undefined, json);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFileExistAsync(
|
|
||||||
filesystem: FileSystem
|
|
||||||
): TsconfigPaths.FileExistsAsync {
|
|
||||||
return (
|
|
||||||
path2: string,
|
|
||||||
callback2: (err?: Error, exists?: boolean) => void
|
|
||||||
) => {
|
|
||||||
filesystem.stat(path2, (err: Error, stats: fs.Stats) => {
|
|
||||||
// If error assume file does not exist
|
|
||||||
if (err) {
|
|
||||||
callback2(undefined, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback2(undefined, stats ? stats.isFile() : false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TsconfigPathsPlugin;
|
|
||||||
@ -36,6 +36,6 @@
|
|||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"semver": "7.3.4",
|
"semver": "7.3.4",
|
||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"tsconfig-paths-webpack-plugin": "3.4.1"
|
"tsconfig-paths-webpack-plugin": "3.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,7 +102,7 @@
|
|||||||
"ts-loader": "^9.2.6",
|
"ts-loader": "^9.2.6",
|
||||||
"ts-node": "~9.1.1",
|
"ts-node": "~9.1.1",
|
||||||
"tsconfig-paths": "^3.9.0",
|
"tsconfig-paths": "^3.9.0",
|
||||||
"tsconfig-paths-webpack-plugin": "3.4.1",
|
"tsconfig-paths-webpack-plugin": "3.5.2",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"webpack": "^5.58.1",
|
"webpack": "^5.58.1",
|
||||||
"webpack-merge": "^5.8.0",
|
"webpack-merge": "^5.8.0",
|
||||||
|
|||||||
@ -6,11 +6,7 @@ import * as CopyWebpackPlugin from 'copy-webpack-plugin';
|
|||||||
import TerserPlugin = require('terser-webpack-plugin');
|
import TerserPlugin = require('terser-webpack-plugin');
|
||||||
import { AssetGlobPattern, BuildBuilderOptions } from './shared-models';
|
import { AssetGlobPattern, BuildBuilderOptions } from './shared-models';
|
||||||
import { getOutputHashFormat } from './hash-format';
|
import { getOutputHashFormat } from './hash-format';
|
||||||
|
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||||
// Inlining tsconfig-paths-webpack-plugin with a patch
|
|
||||||
// See: https://github.com/dividab/tsconfig-paths-webpack-plugin/pull/85
|
|
||||||
// TODO(jack): Remove once the patch lands in original package
|
|
||||||
import { TsconfigPathsPlugin } from './webpack/plugins/tsconfig-paths/tsconfig-paths.plugin';
|
|
||||||
import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||||
|
|
||||||
const IGNORED_WEBPACK_WARNINGS = [
|
const IGNORED_WEBPACK_WARNINGS = [
|
||||||
@ -113,13 +109,11 @@ export function getBaseWebpackPartial(
|
|||||||
extensions,
|
extensions,
|
||||||
alias: getAliases(options),
|
alias: getAliases(options),
|
||||||
plugins: [
|
plugins: [
|
||||||
// TODO Remove the never type when module is updated
|
|
||||||
// PR opened for the proper typing here; https://github.com/dividab/tsconfig-paths-webpack-plugin/pull/66
|
|
||||||
new TsconfigPathsPlugin({
|
new TsconfigPathsPlugin({
|
||||||
configFile: options.tsConfig,
|
configFile: options.tsConfig,
|
||||||
extensions,
|
extensions,
|
||||||
mainFields,
|
mainFields,
|
||||||
}),
|
}) as never, // TODO: Remove never type when 'tsconfig-paths-webpack-plugin' types fixed
|
||||||
],
|
],
|
||||||
mainFields,
|
mainFields,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,83 +0,0 @@
|
|||||||
import { Console } from 'console';
|
|
||||||
import { Chalk } from 'chalk';
|
|
||||||
import { Options } from './tsconfig-paths.options';
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
type InternalLoggerFunc = (whereToLog: any, message: string) => void;
|
|
||||||
|
|
||||||
export type LoggerFunc = (message: string) => void;
|
|
||||||
|
|
||||||
export interface Logger {
|
|
||||||
log: LoggerFunc;
|
|
||||||
logInfo: LoggerFunc;
|
|
||||||
logWarning: LoggerFunc;
|
|
||||||
logError: LoggerFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LogLevel {
|
|
||||||
INFO = 1,
|
|
||||||
WARN = 2,
|
|
||||||
ERROR = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
const stderrConsole = new Console(process.stderr);
|
|
||||||
const stdoutConsole = new Console(process.stdout);
|
|
||||||
|
|
||||||
const doNothingLogger = (_message: string) => {
|
|
||||||
/* Do nothing */
|
|
||||||
};
|
|
||||||
|
|
||||||
const makeLoggerFunc = (options: Options): InternalLoggerFunc =>
|
|
||||||
options.silent
|
|
||||||
? (_whereToLog: Console, _message: string) => {
|
|
||||||
/* Do nothing */
|
|
||||||
}
|
|
||||||
: (whereToLog: Console, message: string) => whereToLog.log(message);
|
|
||||||
|
|
||||||
const makeExternalLogger =
|
|
||||||
(loaderOptions: Options, logger: InternalLoggerFunc) => (message: string) =>
|
|
||||||
logger(
|
|
||||||
loaderOptions.logInfoToStdOut ? stdoutConsole : stderrConsole,
|
|
||||||
message
|
|
||||||
);
|
|
||||||
|
|
||||||
const makeLogInfo = (
|
|
||||||
options: Options,
|
|
||||||
logger: InternalLoggerFunc,
|
|
||||||
green: Chalk
|
|
||||||
) =>
|
|
||||||
LogLevel[options.logLevel] <= LogLevel.INFO
|
|
||||||
? (message: string) =>
|
|
||||||
logger(
|
|
||||||
options.logInfoToStdOut ? stdoutConsole : stderrConsole,
|
|
||||||
green(message)
|
|
||||||
)
|
|
||||||
: doNothingLogger;
|
|
||||||
|
|
||||||
const makeLogError = (
|
|
||||||
options: Options,
|
|
||||||
logger: InternalLoggerFunc,
|
|
||||||
red: Chalk
|
|
||||||
) =>
|
|
||||||
LogLevel[options.logLevel] <= LogLevel.ERROR
|
|
||||||
? (message: string) => logger(stderrConsole, red(message))
|
|
||||||
: doNothingLogger;
|
|
||||||
|
|
||||||
const makeLogWarning = (
|
|
||||||
options: Options,
|
|
||||||
logger: InternalLoggerFunc,
|
|
||||||
yellow: Chalk
|
|
||||||
) =>
|
|
||||||
LogLevel[options.logLevel] <= LogLevel.WARN
|
|
||||||
? (message: string) => logger(stderrConsole, yellow(message))
|
|
||||||
: doNothingLogger;
|
|
||||||
|
|
||||||
export function makeLogger(options: Options, colors: Chalk): Logger {
|
|
||||||
const logger = makeLoggerFunc(options);
|
|
||||||
return {
|
|
||||||
log: makeExternalLogger(options, logger),
|
|
||||||
logInfo: makeLogInfo(options, logger, colors.green),
|
|
||||||
logWarning: makeLogWarning(options, logger, colors.yellow),
|
|
||||||
logError: makeLogError(options, logger, colors.red),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
export type LogLevel = 'INFO' | 'WARN' | 'ERROR';
|
|
||||||
|
|
||||||
export interface Options {
|
|
||||||
readonly configFile: string;
|
|
||||||
readonly extensions: ReadonlyArray<string>;
|
|
||||||
readonly baseUrl: string | undefined;
|
|
||||||
readonly silent: boolean;
|
|
||||||
readonly logLevel: LogLevel;
|
|
||||||
readonly logInfoToStdOut: boolean;
|
|
||||||
readonly context: string | undefined;
|
|
||||||
readonly colors: boolean;
|
|
||||||
readonly mainFields: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
type ValidOptions = keyof Options;
|
|
||||||
const validOptions: ReadonlyArray<ValidOptions> = [
|
|
||||||
'configFile',
|
|
||||||
'extensions',
|
|
||||||
'baseUrl',
|
|
||||||
'silent',
|
|
||||||
'logLevel',
|
|
||||||
'logInfoToStdOut',
|
|
||||||
'context',
|
|
||||||
'mainFields',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes raw options from the webpack config,
|
|
||||||
* validates them and adds defaults for missing options
|
|
||||||
*/
|
|
||||||
export function getOptions(rawOptions: {}): Options {
|
|
||||||
validateOptions(rawOptions);
|
|
||||||
|
|
||||||
const options = makeOptions(rawOptions);
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the supplied loader options.
|
|
||||||
* At present this validates the option names only; in future we may look at validating the values too
|
|
||||||
* @param rawOptions
|
|
||||||
*/
|
|
||||||
function validateOptions(rawOptions: {}): void {
|
|
||||||
const loaderOptionKeys = Object.keys(rawOptions);
|
|
||||||
for (let i = 0; i < loaderOptionKeys.length; i++) {
|
|
||||||
const option = loaderOptionKeys[i];
|
|
||||||
const isUnexpectedOption =
|
|
||||||
(validOptions as ReadonlyArray<string>).indexOf(option) === -1;
|
|
||||||
if (isUnexpectedOption) {
|
|
||||||
throw new Error(`tsconfig-paths-webpack-plugin was supplied with an unexpected loader option: ${option}
|
|
||||||
Please take a look at the options you are supplying; the following are valid options:
|
|
||||||
${validOptions.join(' / ')}
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeOptions(rawOptions: Partial<Options>): Options {
|
|
||||||
const options: Options = {
|
|
||||||
...({
|
|
||||||
configFile: 'tsconfig.json',
|
|
||||||
extensions: ['.ts', '.tsx'],
|
|
||||||
baseUrl: undefined,
|
|
||||||
silent: false,
|
|
||||||
logLevel: 'WARN',
|
|
||||||
logInfoToStdOut: false,
|
|
||||||
context: undefined,
|
|
||||||
colors: true,
|
|
||||||
mainFields: ['main'],
|
|
||||||
} as Options),
|
|
||||||
...rawOptions,
|
|
||||||
};
|
|
||||||
|
|
||||||
const options2: Options = {
|
|
||||||
...options,
|
|
||||||
logLevel: options.logLevel.toUpperCase() as LogLevel,
|
|
||||||
};
|
|
||||||
|
|
||||||
return options2;
|
|
||||||
}
|
|
||||||
@ -1,353 +0,0 @@
|
|||||||
// Adapted from https://github.com/dividab/tsconfig-paths-webpack-plugin
|
|
||||||
import * as chalk from 'chalk';
|
|
||||||
import * as TsconfigPaths from 'tsconfig-paths';
|
|
||||||
import * as path from 'path';
|
|
||||||
import * as Options from './tsconfig-paths.options';
|
|
||||||
import * as Logger from './tsconfig-paths.logger';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import { ResolveContext, ResolveRequest } from 'enhanced-resolve';
|
|
||||||
type ResolvePluginInstance = any;
|
|
||||||
type Resolver = any;
|
|
||||||
|
|
||||||
type FileSystem = Resolver['fileSystem'];
|
|
||||||
type TapAsyncCallback = (
|
|
||||||
request: ResolveRequest,
|
|
||||||
context: ResolveContext,
|
|
||||||
callback: TapAsyncInnerCallback
|
|
||||||
) => void;
|
|
||||||
type TapAsyncInnerCallback = (
|
|
||||||
error?: Error | null | false,
|
|
||||||
result?: null | ResolveRequest
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
export interface LegacyResolverPlugin {
|
|
||||||
readonly apply: (resolver: LegacyResolver) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LegacyResolver {
|
|
||||||
readonly apply: (plugin: LegacyResolverPlugin) => void;
|
|
||||||
readonly plugin: (source: string, cb: ResolverCallbackLegacy) => void;
|
|
||||||
readonly doResolve: doResolveLegacy | doResolve;
|
|
||||||
readonly join: (relativePath: string, innerRequest: Request) => Request;
|
|
||||||
readonly fileSystem: LegacyResolverFileSystem;
|
|
||||||
readonly getHook: (hook: string) => Tapable;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type doResolveLegacy = (
|
|
||||||
target: string,
|
|
||||||
req: Request,
|
|
||||||
desc: string,
|
|
||||||
callback: Callback
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
export type doResolve = (
|
|
||||||
hook: Tapable,
|
|
||||||
req: Request,
|
|
||||||
message: string,
|
|
||||||
resolveContext: LegacyResolveContext,
|
|
||||||
callback: Callback
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
export type ReadJsonCallback = (error: Error | undefined, result?: {}) => void;
|
|
||||||
|
|
||||||
export type ReadJson = (path2: string, callback: ReadJsonCallback) => void;
|
|
||||||
|
|
||||||
export type LegacyResolverFileSystem = typeof fs & { readJson?: ReadJson };
|
|
||||||
|
|
||||||
export interface LegacyResolveContext {
|
|
||||||
log?: string;
|
|
||||||
stack?: string;
|
|
||||||
missing?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Tapable {
|
|
||||||
readonly tapAsync: (
|
|
||||||
options: TapableOptions,
|
|
||||||
callback: TapAsyncCallback
|
|
||||||
) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TapableOptions {
|
|
||||||
readonly name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ResolverCallbackLegacy = (
|
|
||||||
request: Request,
|
|
||||||
callback: Callback
|
|
||||||
) => void;
|
|
||||||
export type ResolverCallback = (
|
|
||||||
request: Request,
|
|
||||||
resolveContext: LegacyResolveContext,
|
|
||||||
callback: Callback
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
type CreateInnerCallback = (
|
|
||||||
callback: Callback,
|
|
||||||
options: Callback,
|
|
||||||
message?: string,
|
|
||||||
messageOptional?: string
|
|
||||||
) => Callback;
|
|
||||||
|
|
||||||
type CreateInnerContext = (
|
|
||||||
options: {
|
|
||||||
log?: string;
|
|
||||||
stack?: string;
|
|
||||||
missing?: string;
|
|
||||||
},
|
|
||||||
message?: string,
|
|
||||||
messageOptional?: string
|
|
||||||
) => ResolveContext;
|
|
||||||
|
|
||||||
type getInnerRequest = (
|
|
||||||
resolver: Resolver | LegacyResolver,
|
|
||||||
request: ResolveRequest | Request
|
|
||||||
) => string;
|
|
||||||
|
|
||||||
export interface Request {
|
|
||||||
readonly request?: Request | string;
|
|
||||||
readonly relativePath: string;
|
|
||||||
readonly path: string;
|
|
||||||
readonly context: {
|
|
||||||
readonly issuer: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Callback {
|
|
||||||
(err?: Error, result?: string): void;
|
|
||||||
|
|
||||||
log?: string;
|
|
||||||
stack?: string;
|
|
||||||
missing?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getInnerRequest: getInnerRequest = require('enhanced-resolve/lib/getInnerRequest');
|
|
||||||
|
|
||||||
export class TsconfigPathsPlugin implements ResolvePluginInstance {
|
|
||||||
source: string = 'described-resolve';
|
|
||||||
target: string = 'resolve';
|
|
||||||
|
|
||||||
log: Logger.Logger;
|
|
||||||
baseUrl: string;
|
|
||||||
absoluteBaseUrl: string;
|
|
||||||
extensions: ReadonlyArray<string>;
|
|
||||||
|
|
||||||
matchPath: TsconfigPaths.MatchPathAsync;
|
|
||||||
|
|
||||||
constructor(rawOptions: Partial<Options.Options> = {}) {
|
|
||||||
const options = Options.getOptions(rawOptions);
|
|
||||||
|
|
||||||
this.extensions = options.extensions;
|
|
||||||
|
|
||||||
// const colors = new chalk.constructor({ enabled: options.colors });
|
|
||||||
|
|
||||||
this.log = Logger.makeLogger(
|
|
||||||
options,
|
|
||||||
new chalk.Instance({ level: options.colors ? undefined : 0 })
|
|
||||||
);
|
|
||||||
|
|
||||||
const context = options.context || process.cwd();
|
|
||||||
const loadFrom = options.configFile || context;
|
|
||||||
|
|
||||||
const loadResult = TsconfigPaths.loadConfig(loadFrom);
|
|
||||||
if (loadResult.resultType === 'failed') {
|
|
||||||
this.log.logError(`Failed to load ${loadFrom}: ${loadResult.message}`);
|
|
||||||
} else {
|
|
||||||
this.log.logInfo(
|
|
||||||
`tsconfig-paths-webpack-plugin: Using config file at ${loadResult.configFileAbsolutePath}`
|
|
||||||
);
|
|
||||||
this.baseUrl = options.baseUrl || loadResult.baseUrl;
|
|
||||||
this.absoluteBaseUrl = options.baseUrl
|
|
||||||
? path.resolve(options.baseUrl)
|
|
||||||
: loadResult.absoluteBaseUrl;
|
|
||||||
this.matchPath = TsconfigPaths.createMatchPathAsync(
|
|
||||||
this.absoluteBaseUrl,
|
|
||||||
loadResult.paths,
|
|
||||||
options.mainFields
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(resolver: Resolver): void {
|
|
||||||
if (!resolver) {
|
|
||||||
this.log.logWarning(
|
|
||||||
'tsconfig-paths-webpack-plugin: Found no resolver, not applying tsconfig-paths-webpack-plugin'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { baseUrl } = this;
|
|
||||||
|
|
||||||
if (!baseUrl) {
|
|
||||||
// Nothing to do if there is no baseUrl
|
|
||||||
this.log.logWarning(
|
|
||||||
'tsconfig-paths-webpack-plugin: Found no baseUrl in tsconfig.json, not applying tsconfig-paths-webpack-plugin'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The file system only exists when the plugin is in the resolve context. This means it's also properly placed in the resolve.plugins array.
|
|
||||||
// If not, we should warn the user that this plugin should be placed in resolve.plugins and not the plugins array of the root config for example.
|
|
||||||
// This should hopefully prevent issues like: https://github.com/dividab/tsconfig-paths-webpack-plugin/issues/9
|
|
||||||
if (!('fileSystem' in resolver)) {
|
|
||||||
this.log.logWarning(
|
|
||||||
'tsconfig-paths-webpack-plugin: No file system found on resolver.' +
|
|
||||||
" Please make sure you've placed the plugin in the correct part of the configuration." +
|
|
||||||
' This plugin is a resolver plugin and should be placed in the resolve part of the Webpack configuration.'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolver.getHook(this.source).tapAsync(
|
|
||||||
{ name: 'TsconfigPathsPlugin' },
|
|
||||||
// @ts-ignore
|
|
||||||
createPluginCallback(
|
|
||||||
this.matchPath,
|
|
||||||
resolver,
|
|
||||||
this.absoluteBaseUrl,
|
|
||||||
// @ts-ignore
|
|
||||||
resolver.getHook(this.target),
|
|
||||||
this.extensions
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createPluginCallback(
|
|
||||||
matchPath: TsconfigPaths.MatchPathAsync,
|
|
||||||
resolver: Resolver,
|
|
||||||
absoluteBaseUrl: string,
|
|
||||||
hook: Tapable,
|
|
||||||
extensions: ReadonlyArray<string>
|
|
||||||
): TapAsyncCallback {
|
|
||||||
const fileExistAsync = createFileExistAsync(resolver.fileSystem);
|
|
||||||
const readJsonAsync = createReadJsonAsync(resolver.fileSystem);
|
|
||||||
return (
|
|
||||||
request: ResolveRequest,
|
|
||||||
resolveContext: ResolveContext,
|
|
||||||
callback: TapAsyncInnerCallback
|
|
||||||
) => {
|
|
||||||
const innerRequest = getInnerRequest(resolver, request);
|
|
||||||
|
|
||||||
// innerRequest never starts with '.' in new enhanced-resolve
|
|
||||||
if (
|
|
||||||
!innerRequest ||
|
|
||||||
request?.request?.startsWith('.') ||
|
|
||||||
request?.request?.startsWith('..')
|
|
||||||
) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
matchPath(
|
|
||||||
innerRequest,
|
|
||||||
readJsonAsync,
|
|
||||||
fileExistAsync,
|
|
||||||
extensions,
|
|
||||||
(err, foundMatch) => {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundMatch) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
const newRequest = {
|
|
||||||
...request,
|
|
||||||
request: foundMatch,
|
|
||||||
path: absoluteBaseUrl,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only at this point we are sure we are dealing with the latest Webpack version (>= 4.0.0)
|
|
||||||
// So only now can we require the createInnerContext function.
|
|
||||||
// (It doesn't exist in legacy versions)
|
|
||||||
const createInnerContext: CreateInnerContext = require('enhanced-resolve/lib/createInnerContext');
|
|
||||||
|
|
||||||
return resolver.doResolve(
|
|
||||||
hook,
|
|
||||||
newRequest as never,
|
|
||||||
`Resolved request '${innerRequest}' to '${foundMatch}' using tsconfig.json paths mapping`,
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
createInnerContext({ ...(resolveContext as any) }),
|
|
||||||
(err2: Error, result2: ResolveRequest): void => {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
callback(undefined, result2);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readJson(
|
|
||||||
fileSystem: FileSystem,
|
|
||||||
path2: string,
|
|
||||||
callback: ReadJsonCallback
|
|
||||||
): void {
|
|
||||||
if ('readJson' in fileSystem && fileSystem.readJson) {
|
|
||||||
return fileSystem.readJson(path2, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileSystem.readFile(path2, (err, buf) => {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
let data;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// @ts-ignore This will crash if buf is undefined, which I guess it can be...
|
|
||||||
data = JSON.parse(buf.toString('utf-8'));
|
|
||||||
} catch (e) {
|
|
||||||
return callback(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback(undefined, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createReadJsonAsync(
|
|
||||||
filesystem: FileSystem
|
|
||||||
): TsconfigPaths.ReadJsonAsync {
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
return (path2: string, callback2: (err?: Error, content?: any) => void) => {
|
|
||||||
readJson(filesystem, path2, (err, json) => {
|
|
||||||
// If error assume file does not exist
|
|
||||||
if (err || !json) {
|
|
||||||
callback2();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback2(undefined, json);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFileExistAsync(
|
|
||||||
filesystem: FileSystem
|
|
||||||
): TsconfigPaths.FileExistsAsync {
|
|
||||||
return (
|
|
||||||
path2: string,
|
|
||||||
callback2: (err?: Error, exists?: boolean) => void
|
|
||||||
) => {
|
|
||||||
filesystem.stat(path2, (err: Error, stats: fs.Stats) => {
|
|
||||||
// If error assume file does not exist
|
|
||||||
if (err) {
|
|
||||||
callback2(undefined, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback2(undefined, stats ? stats.isFile() : false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TsconfigPathsPlugin;
|
|
||||||
@ -22244,7 +22244,7 @@ tsconfig-paths-webpack-plugin@3.4.1:
|
|||||||
enhanced-resolve "^5.7.0"
|
enhanced-resolve "^5.7.0"
|
||||||
tsconfig-paths "^3.9.0"
|
tsconfig-paths "^3.9.0"
|
||||||
|
|
||||||
tsconfig-paths-webpack-plugin@^3.3.0:
|
tsconfig-paths-webpack-plugin@3.5.2, tsconfig-paths-webpack-plugin@^3.3.0:
|
||||||
version "3.5.2"
|
version "3.5.2"
|
||||||
resolved "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz"
|
resolved "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz"
|
||||||
integrity sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==
|
integrity sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user