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-node": "9.1.1",
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
"tsconfig-paths-webpack-plugin": "3.4.1",
|
||||
"tsconfig-paths-webpack-plugin": "3.5.2",
|
||||
"tslib": "^2.3.0",
|
||||
"tslint": "6.1.3",
|
||||
"tslint-to-eslint-config": "^2.4.0",
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
"enhanced-resolve": "^5.8.3",
|
||||
"ts-loader": "^9.2.6",
|
||||
"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",
|
||||
"fork-ts-checker-webpack-plugin": "6.2.10",
|
||||
"rxjs": "^6.5.4",
|
||||
|
||||
@ -2,16 +2,11 @@ import { createWebpackConfig, prepareConfig } from './config';
|
||||
import { NextBuildBuilderOptions } from '@nrwl/next';
|
||||
import { dirname } from 'path';
|
||||
import { importConstants } from './require-shim';
|
||||
// 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 '@nrwl/web/src/utils/webpack/plugins/tsconfig-paths/tsconfig-paths.plugin';
|
||||
import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||
|
||||
const { PHASE_PRODUCTION_BUILD } = importConstants();
|
||||
|
||||
jest.mock(
|
||||
'@nrwl/web/src/utils/webpack/plugins/tsconfig-paths/tsconfig-paths.plugin'
|
||||
);
|
||||
jest.mock('tsconfig-paths-webpack-plugin');
|
||||
jest.mock('next/dist/server/config', () => ({
|
||||
__esModule: true,
|
||||
default: () => ({
|
||||
|
||||
@ -10,7 +10,7 @@ import type {
|
||||
PHASE_PRODUCTION_SERVER,
|
||||
} from 'next/dist/shared/lib/constants';
|
||||
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 {
|
||||
FileReplacement,
|
||||
@ -71,7 +71,7 @@ export function createWebpackConfig(
|
||||
configFile: tsConfigPath,
|
||||
extensions,
|
||||
mainFields,
|
||||
}),
|
||||
}) as never, // TODO: Remove never type when 'tsconfig-paths-webpack-plugin' types fixed
|
||||
];
|
||||
|
||||
fileReplacements
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
"tree-kill": "1.2.2",
|
||||
"ts-loader": "^9.2.6",
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
"tsconfig-paths-webpack-plugin": "3.4.1",
|
||||
"tsconfig-paths-webpack-plugin": "3.5.2",
|
||||
"tslib": "^2.3.0",
|
||||
"webpack": "^5.58.1",
|
||||
"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 { 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', () => ({
|
||||
runWebpack: jest.fn(),
|
||||
}));
|
||||
|
||||
@ -8,11 +8,7 @@ import { BuildBuilderOptions } from './types';
|
||||
import { loadTsPlugins } from './load-ts-plugins';
|
||||
import CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-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 { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||
|
||||
export const OUT_FILENAME_TEMPLATE = '[name].js';
|
||||
|
||||
@ -85,11 +81,11 @@ export function getBaseWebpackPartial(
|
||||
extensions,
|
||||
alias: getAliases(options),
|
||||
plugins: [
|
||||
new TsConfigPathsPlugin({
|
||||
new TsconfigPathsPlugin({
|
||||
configFile: options.tsConfig,
|
||||
extensions,
|
||||
mainFields,
|
||||
}),
|
||||
}) as never, // TODO: Remove never type when 'tsconfig-paths-webpack-plugin' types fixed
|
||||
],
|
||||
mainFields,
|
||||
},
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { join } from 'path';
|
||||
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';
|
||||
|
||||
jest.mock('./webpack/plugins/tsconfig-paths/tsconfig-paths.plugin');
|
||||
jest.mock('tsconfig-paths-webpack-plugin');
|
||||
jest.mock('@nrwl/tao/src/utils/app-root', () => ({
|
||||
get appRootPath() {
|
||||
return join(__dirname, '../../../..');
|
||||
@ -21,7 +21,7 @@ describe('getNodePartial', () => {
|
||||
fileReplacements: [],
|
||||
statsJson: false,
|
||||
};
|
||||
(<any>TsConfigPathsPlugin).mockImplementation(
|
||||
(<any>TsconfigPathsPlugin).mockImplementation(
|
||||
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",
|
||||
"semver": "7.3.4",
|
||||
"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-node": "~9.1.1",
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
"tsconfig-paths-webpack-plugin": "3.4.1",
|
||||
"tsconfig-paths-webpack-plugin": "3.5.2",
|
||||
"tslib": "^2.3.0",
|
||||
"webpack": "^5.58.1",
|
||||
"webpack-merge": "^5.8.0",
|
||||
|
||||
@ -6,11 +6,7 @@ import * as CopyWebpackPlugin from 'copy-webpack-plugin';
|
||||
import TerserPlugin = require('terser-webpack-plugin');
|
||||
import { AssetGlobPattern, BuildBuilderOptions } from './shared-models';
|
||||
import { getOutputHashFormat } from './hash-format';
|
||||
|
||||
// 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 { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin';
|
||||
import ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
|
||||
const IGNORED_WEBPACK_WARNINGS = [
|
||||
@ -113,13 +109,11 @@ export function getBaseWebpackPartial(
|
||||
extensions,
|
||||
alias: getAliases(options),
|
||||
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({
|
||||
configFile: options.tsConfig,
|
||||
extensions,
|
||||
mainFields,
|
||||
}),
|
||||
}) as never, // TODO: Remove never type when 'tsconfig-paths-webpack-plugin' types fixed
|
||||
],
|
||||
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"
|
||||
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"
|
||||
resolved "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz"
|
||||
integrity sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user