Skip to content

Commit

Permalink
Improve absolute path handling
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Mar 29, 2021
1 parent 85a3724 commit 486a13f
Show file tree
Hide file tree
Showing 27 changed files with 404 additions and 45 deletions.
6 changes: 5 additions & 1 deletion src/Chunk.ts
Expand Up @@ -1246,7 +1246,11 @@ export default class Chunk {
}
}

private setIdentifierRenderResolutions({ format, interop, namespaceToStringTag }: NormalizedOutputOptions) {
private setIdentifierRenderResolutions({
format,
interop,
namespaceToStringTag
}: NormalizedOutputOptions) {
const syntheticExports = new Set<SyntheticNamedExportVariable>();
for (const exportName of this.getExportNames()) {
const exportVariable = this.exportsByName[exportName];
Expand Down
15 changes: 6 additions & 9 deletions src/ExternalModule.ts
Expand Up @@ -7,7 +7,7 @@ import {
} from './rollup/types';
import { EMPTY_ARRAY } from './utils/blank';
import { makeLegal } from './utils/identifierHelpers';
import { isAbsolute, normalize, relative } from './utils/path';
import { normalize, relative } from './utils/path';

export default class ExternalModule {
chunk: void;
Expand All @@ -23,7 +23,6 @@ export default class ExternalModule {
nameSuggestions: { [name: string]: number };
reexported = false;
renderPath: string = undefined as any;
renormalizeRenderPath = false;
suggestedVariableName: string;
used = false;
variableName = '';
Expand All @@ -32,7 +31,8 @@ export default class ExternalModule {
private readonly options: NormalizedInputOptions,
public readonly id: string,
hasModuleSideEffects: boolean | 'no-treeshake',
meta: CustomPluginOptions
meta: CustomPluginOptions,
public renormalizeRenderPath: boolean
) {
this.execIndex = Infinity;
this.suggestedVariableName = makeLegal(id.split(/[\\/]/).pop()!);
Expand Down Expand Up @@ -76,12 +76,9 @@ export default class ExternalModule {
this.renderPath =
typeof options.paths === 'function' ? options.paths(this.id) : options.paths[this.id];
if (!this.renderPath) {
if (!isAbsolute(this.id)) {
this.renderPath = this.id;
} else {
this.renderPath = normalize(relative(inputBase, this.id));
this.renormalizeRenderPath = true;
}
this.renderPath = this.renormalizeRenderPath
? normalize(relative(inputBase, this.id))
: this.id;
}
return this.renderPath;
}
Expand Down
87 changes: 69 additions & 18 deletions src/ModuleLoader.ts
Expand Up @@ -6,8 +6,9 @@ import {
CustomPluginOptions,
EmittedChunk,
HasModuleSideEffects,
ModuleOptions,
NormalizedInputOptions,
PartialResolvedId,
PartialNull,
Plugin,
ResolvedId,
ResolveIdResult,
Expand All @@ -27,7 +28,7 @@ import {
errUnresolvedImportTreatedAsExternal
} from './utils/error';
import { readFile } from './utils/fs';
import { isRelative, resolve } from './utils/path';
import { isAbsolute, isRelative, resolve } from './utils/path';
import { PluginDriver } from './utils/PluginDriver';
import relativeId from './utils/relativeId';
import { resolveId } from './utils/resolveId';
Expand All @@ -41,6 +42,11 @@ export interface UnresolvedModule {
name: string | null;
}

type NormalizedResolveIdWithoutDefaults = Partial<PartialNull<ModuleOptions>> & {
external?: boolean | 'absolute';
id: string;
};

export class ModuleLoader {
private readonly hasModuleSideEffects: HasModuleSideEffects;
private readonly implicitEntryModules = new Set<Module>();
Expand Down Expand Up @@ -160,9 +166,11 @@ export class ModuleLoader {
source
)
);
}
};

private addDefaultsToResolvedId(resolvedId: PartialResolvedId | null): ResolvedId | null {
private addDefaultsToResolvedId(
resolvedId: NormalizedResolveIdWithoutDefaults | null
): ResolvedId | null {
if (!resolvedId) {
return null;
}
Expand All @@ -172,7 +180,7 @@ export class ModuleLoader {
id: resolvedId.id,
meta: resolvedId.meta || EMPTY_OBJECT,
moduleSideEffects:
resolvedId.moduleSideEffects ?? this.hasModuleSideEffects(resolvedId.id, external),
resolvedId.moduleSideEffects ?? this.hasModuleSideEffects(resolvedId.id, !!external),
syntheticNamedExports: resolvedId.syntheticNamedExports ?? false
};
}
Expand Down Expand Up @@ -338,19 +346,21 @@ export class ModuleLoader {
resolvedId: ResolvedId
): Promise<Module | ExternalModule> {
if (resolvedId.external) {
if (!this.modulesById.has(resolvedId.id)) {
const { external, id, moduleSideEffects, meta } = resolvedId;
if (!this.modulesById.has(id)) {
this.modulesById.set(
resolvedId.id,
id,
new ExternalModule(
this.options,
resolvedId.id,
resolvedId.moduleSideEffects,
resolvedId.meta
id,
moduleSideEffects,
meta,
external !== 'absolute' && isAbsolute(id)
)
);
}

const externalModule = this.modulesById.get(resolvedId.id);
const externalModule = this.modulesById.get(id);
if (!(externalModule instanceof ExternalModule)) {
return error(errInternalIdCannotBeExternal(source, importer));
}
Expand Down Expand Up @@ -381,31 +391,58 @@ export class ModuleLoader {
}
}

/* For plugins when resolveIdResult.id is absolute (otherwise external is true)
external | normalizeExternalPaths | result
true | true | true
true | 'relative' | 'absolute'
true | false | 'absolute'
'normalize' | true | true
'normalize' | 'relative' | true
'normalize' | false | true
'absolute' | true | 'absolute'
'absolute' | 'relative' | 'absolute'
'absolute' | false | 'absolute'
*/
private getNormalizedResolvedIdWithoutDefaults(
resolveIdResult: ResolveIdResult,
importer: string | undefined,
source: string
): (PartialResolvedId & { external: boolean }) | null {
): NormalizedResolveIdWithoutDefaults | null {
const { normalizeExternalPaths } = this.options;
if (resolveIdResult) {
if (typeof resolveIdResult === 'object') {
const external =
resolveIdResult.external || this.options.external(resolveIdResult.id, importer, true);
return {
...resolveIdResult,
external:
resolveIdResult.external || this.options.external(resolveIdResult.id, importer, true)
external &&
(external === 'normalize' ||
!isAbsolute(resolveIdResult.id) ||
(external === true &&
isNotAbsoluteExternal(resolveIdResult.id, source, normalizeExternalPaths)) ||
'absolute')
};
}

const external = this.options.external(resolveIdResult, importer, true);
return {
external,
id: external ? normalizeRelativeExternalId(resolveIdResult, importer) : resolveIdResult
external:
external &&
(isNotAbsoluteExternal(resolveIdResult, source, normalizeExternalPaths) || 'absolute'),
id:
external && normalizeExternalPaths
? normalizeRelativeExternalId(resolveIdResult, importer)
: resolveIdResult
};
}
const id = normalizeRelativeExternalId(source, importer);

const id = normalizeExternalPaths ? normalizeRelativeExternalId(source, importer) : source;
if (resolveIdResult !== false && !this.options.external(id, importer, true)) {
return null;
}
return {
external: true,
external: isNotAbsoluteExternal(id, source, normalizeExternalPaths) || 'absolute',
id
};
}
Expand Down Expand Up @@ -469,7 +506,9 @@ export class ModuleLoader {
}
return this.fetchModule(
this.addDefaultsToResolvedId(
typeof resolveIdResult === 'object' ? resolveIdResult : { id: resolveIdResult }
typeof resolveIdResult === 'object'
? (resolveIdResult as NormalizedResolveIdWithoutDefaults)
: { id: resolveIdResult }
)!,
undefined,
isEntry
Expand Down Expand Up @@ -541,3 +580,15 @@ function addChunkNamesToModule(
}
}
}

function isNotAbsoluteExternal(
id: string,
source: string,
normalizeExternalPaths: boolean | 'relative'
) {
return (
normalizeExternalPaths === true ||
(normalizeExternalPaths === 'relative' && isRelative(source)) ||
!isAbsolute(id)
);
}
6 changes: 4 additions & 2 deletions src/rollup/types.d.ts
Expand Up @@ -219,7 +219,7 @@ export interface PluginContextMeta {
}

export interface ResolvedId extends ModuleOptions {
external: boolean;
external: boolean | 'absolute';
id: string;
}

Expand All @@ -228,7 +228,7 @@ export interface ResolvedIdMap {
}

interface PartialResolvedId extends Partial<PartialNull<ModuleOptions>> {
external?: boolean;
external?: boolean | 'absolute' | 'normalize';
id: string;
}

Expand Down Expand Up @@ -531,6 +531,7 @@ export interface InputOptions {
/** @deprecated Use the "manualChunks" output option instead. */
manualChunks?: ManualChunksOption;
moduleContext?: ((id: string) => string | null | undefined) | { [id: string]: string };
normalizeExternalPaths?: boolean | 'relative';
onwarn?: WarningHandlerWithDefault;
perf?: boolean;
plugins?: Plugin[];
Expand All @@ -557,6 +558,7 @@ export interface NormalizedInputOptions {
/** @deprecated Use the "manualChunks" output option instead. */
manualChunks: ManualChunksOption | undefined;
moduleContext: (id: string) => string;
normalizeExternalPaths: boolean | 'relative';
onwarn: WarningHandler;
perf: boolean;
plugins: Plugin[];
Expand Down
1 change: 1 addition & 0 deletions src/utils/options/mergeOptions.ts
Expand Up @@ -108,6 +108,7 @@ function mergeInputOptions(
input: getOption('input') || [],
manualChunks: getOption('manualChunks'),
moduleContext: getOption('moduleContext'),
normalizeExternalPaths: getOption('normalizeExternalPaths'),
onwarn: getOnWarn(config, defaultOnWarnHandler),
perf: getOption('perf'),
plugins: ensureArray(config.plugins) as Plugin[],
Expand Down
4 changes: 3 additions & 1 deletion src/utils/options/normalizeInputOptions.ts
Expand Up @@ -51,6 +51,8 @@ export function normalizeInputOptions(
input: getInput(config),
manualChunks: getManualChunks(config, onwarn, strictDeprecations),
moduleContext: getModuleContext(config, context),
normalizeExternalPaths:
(config.normalizeExternalPaths as boolean | 'relative' | undefined) ?? true,
onwarn,
perf: (config.perf as boolean | undefined) || false,
plugins: ensureArray(config.plugins) as Plugin[],
Expand Down Expand Up @@ -262,7 +264,7 @@ const getTreeshake = (
warn
),
propertyReadSideEffects:
configTreeshake.propertyReadSideEffects === 'always' && 'always' ||
(configTreeshake.propertyReadSideEffects === 'always' && 'always') ||
configTreeshake.propertyReadSideEffects !== false,
tryCatchDeoptimization: configTreeshake.tryCatchDeoptimization !== false,
unknownGlobalSideEffects: configTreeshake.unknownGlobalSideEffects !== false
Expand Down
@@ -0,0 +1,22 @@
const path = require('path');

module.exports = {
description: 'does not normalize external paths when set to false',
options: {
normalizeExternalPaths: false,
external(id) {
if (['./relativeUnresolved.js', '../relativeUnresolved.js', '/absolute.js'].includes(id))
return true;
},
plugins: {
resolveId(source) {
if (source.endsWith('/pluginDirect.js')) return false;
if (source.endsWith('/pluginTrue.js')) return { id: '/pluginTrue.js', external: true };
if (source.endsWith('/pluginAbsolute.js'))
return { id: '/pluginAbsolute.js', external: 'absolute' };
if (source.endsWith('/pluginNormalize.js'))
return { id: path.join(__dirname, 'pluginNormalize.js'), external: 'normalize' };
}
}
}
};
@@ -0,0 +1,32 @@
import { relativeUnresolved as relativeUnresolved$1 } from './relativeUnresolved.js';
import { absolute } from '/absolute.js';
import { pluginDirect as pluginDirect$1 } from './pluginDirect.js';
import { pluginTrue } from '/pluginTrue.js';
import { pluginAbsolute } from '/pluginAbsolute.js';
import { pluginNormalize } from './pluginNormalize.js';
import { relativeUnresolved } from '../relativeUnresolved.js';
import { pluginDirect } from '../pluginDirect.js';

console.log(
'nested',
relativeUnresolved,
relativeMissing,
relativeExisting,
absolute,
pluginDirect,
pluginTrue,
pluginAbsolute,
pluginNormalize
);

console.log(
'main',
relativeUnresolved$1,
relativeMissing,
relativeExisting,
absolute,
pluginDirect$1,
pluginTrue,
pluginAbsolute,
pluginNormalize
);
19 changes: 19 additions & 0 deletions test/form/samples/normalize-external-paths/normalize-false/main.js
@@ -0,0 +1,19 @@
import { relativeUnresolved } from './relativeUnresolved.js';
import { absolute } from '/absolute.js';
import { pluginDirect } from './pluginDirect.js';
import { pluginTrue } from './pluginTrue.js';
import { pluginAbsolute } from './pluginAbsolute.js';
import { pluginNormalize } from './pluginNormalize.js';
import './nested/nested.js';

console.log(
'main',
relativeUnresolved,
relativeMissing,
relativeExisting,
absolute,
pluginDirect,
pluginTrue,
pluginAbsolute,
pluginNormalize
);
@@ -0,0 +1,18 @@
import { relativeUnresolved } from '../relativeUnresolved.js';
import { absolute } from '/absolute.js';
import { pluginDirect } from '../pluginDirect.js';
import { pluginTrue } from '../pluginTrue.js';
import { pluginAbsolute } from '../pluginAbsolute.js';
import { pluginNormalize } from '../pluginNormalize.js';

console.log(
'nested',
relativeUnresolved,
relativeMissing,
relativeExisting,
absolute,
pluginDirect,
pluginTrue,
pluginAbsolute,
pluginNormalize
);

0 comments on commit 486a13f

Please sign in to comment.