Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More bugs #6567

Merged
merged 5 commits into from
Jul 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 12 additions & 16 deletions packages/core/core/src/Transformation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import type {
FilePath,
FileCreateInvalidation,
GenerateOutput,
Transformer,
TransformerResult,
Expand All @@ -12,7 +11,6 @@ import type {
import type {WorkerApi} from '@parcel/workers';
import type {
Asset as AssetValue,
AssetGroup,
TransformationRequest,
RequestInvalidation,
Config,
Expand Down Expand Up @@ -660,19 +658,13 @@ export default class Transformation {
const logger = new PluginLogger({origin: transformerName});

const resolve = async (from: FilePath, to: string): Promise<FilePath> => {
let result: {|
assetGroup: AssetGroup,
invalidateOnFileCreate?: Array<FileCreateInvalidation>,
invalidateOnFileChange?: Array<FilePath>,
|} = nullthrows(
await pipeline.resolverRunner.resolve(
createDependency(this.options.projectRoot, {
env: asset.value.env,
specifier: to,
specifierType: 'esm', // ???
sourcePath: from,
}),
),
let result = await pipeline.resolverRunner.resolve(
createDependency(this.options.projectRoot, {
env: asset.value.env,
specifier: to,
specifierType: 'esm', // ???
sourcePath: from,
}),
);

if (result.invalidateOnFileCreate) {
Expand All @@ -694,9 +686,13 @@ export default class Transformation {
}
}

if (result.diagnostics && result.diagnostics.length > 0) {
throw new ThrowableDiagnostic({diagnostic: result.diagnostics});
}

return fromProjectPath(
this.options.projectRoot,
result.assetGroup.filePath,
nullthrows(result.assetGroup).filePath,
);
};

Expand Down
121 changes: 79 additions & 42 deletions packages/core/core/src/requests/PathRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,28 +72,35 @@ async function run({input, api, options}: RunOpts) {
options,
config,
});
let result: ?ResolverResult = await resolverRunner.resolve(input.dependency);

if (result != null) {
if (result.invalidateOnFileCreate) {
for (let file of result.invalidateOnFileCreate) {
api.invalidateOnFileCreate(
invalidateOnFileCreateToInternal(options.projectRoot, file),
);
}
let result: ResolverResult = await resolverRunner.resolve(input.dependency);

if (result.invalidateOnFileCreate) {
for (let file of result.invalidateOnFileCreate) {
api.invalidateOnFileCreate(
invalidateOnFileCreateToInternal(options.projectRoot, file),
);
}
}

if (result.invalidateOnFileChange) {
for (let filePath of result.invalidateOnFileChange) {
let pp = toProjectPath(options.projectRoot, filePath);
api.invalidateOnFileUpdate(pp);
api.invalidateOnFileDelete(pp);
}
if (result.invalidateOnFileChange) {
for (let filePath of result.invalidateOnFileChange) {
let pp = toProjectPath(options.projectRoot, filePath);
api.invalidateOnFileUpdate(pp);
api.invalidateOnFileDelete(pp);
}
}

if (result.assetGroup) {
api.invalidateOnFileDelete(result.assetGroup.filePath);
return result.assetGroup;
}

if (result.diagnostics && result.diagnostics.length > 0) {
let err = new ThrowableDiagnostic({diagnostic: result.diagnostics});
// $FlowFixMe[prop-missing]
err.code = 'MODULE_NOT_FOUND';
throw err;
}
}

type ResolverRunnerOpts = {|
Expand All @@ -102,9 +109,10 @@ type ResolverRunnerOpts = {|
|};

type ResolverResult = {|
assetGroup: AssetGroup,
assetGroup: ?AssetGroup,
invalidateOnFileCreate?: Array<FileCreateInvalidation>,
invalidateOnFileChange?: Array<FilePath>,
diagnostics?: Array<Diagnostic>,
|};

export class ResolverRunner {
Expand All @@ -118,10 +126,10 @@ export class ResolverRunner {
this.pluginOptions = new PluginOptions(this.options);
}

async getThrowableDiagnostic(
async getDiagnostic(
dependency: Dependency,
message: string,
): Async<ThrowableDiagnostic> {
): Async<Diagnostic> {
let diagnostic: Diagnostic = {
message,
origin: '@parcel/core',
Expand All @@ -143,10 +151,10 @@ export class ResolverRunner {
];
}

return new ThrowableDiagnostic({diagnostic});
return diagnostic;
}

async resolve(dependency: Dependency): Promise<?ResolverResult> {
async resolve(dependency: Dependency): Promise<ResolverResult> {
let dep = new PublicDependency(dependency, this.options);
report({
type: 'buildProgress',
Expand Down Expand Up @@ -174,24 +182,29 @@ export class ResolverRunner {
if (dep.specifierType === 'url') {
// This may be a url protocol or scheme rather than a pipeline, such as
// `url('http://example.com/foo.png')`
return null;
return {assetGroup: null};
} else {
throw await this.getThrowableDiagnostic(
dependency,
md`Unknown pipeline: ${pipeline}.`,
);
return {
assetGroup: null,
diagnostics: [
await this.getDiagnostic(
dependency,
md`Unknown pipeline: ${pipeline}.`,
),
],
};
}
}
}
} else {
if (dep.specifierType === 'url') {
if (dependency.specifier.startsWith('//')) {
// A protocol-relative URL, e.g `url('//example.com/foo.png')`
return null;
return {assetGroup: null};
}
if (dependency.specifier.startsWith('#')) {
// An ID-only URL, e.g. `url(#clip-path)` for CSS rules
return null;
return {assetGroup: null};
}
}
filePath = dependency.specifier;
Expand All @@ -201,10 +214,15 @@ export class ResolverRunner {
if (dep.specifierType === 'url') {
let parsed = URL.parse(filePath);
if (typeof parsed.pathname !== 'string') {
throw await this.getThrowableDiagnostic(
dependency,
md`Received URL without a pathname ${filePath}.`,
);
return {
assetGroup: null,
diagnostics: [
await this.getDiagnostic(
dependency,
md`Received URL without a pathname ${filePath}.`,
),
],
};
}
filePath = decodeURIComponent(parsed.pathname);
if (parsed.query != null) {
Expand All @@ -226,6 +244,8 @@ export class ResolverRunner {
filePath = path.join(this.options.projectRoot, filePath);
}
let diagnostics: Array<Diagnostic> = [];
let invalidateOnFileCreate = [];
let invalidateOnFileChange = [];
for (let resolver of resolvers) {
try {
let result = await resolver.plugin.resolve({
Expand All @@ -249,8 +269,20 @@ export class ResolverRunner {
dependency.priority = Priority[result.priority];
}

if (result.invalidateOnFileCreate) {
invalidateOnFileCreate.push(...result.invalidateOnFileCreate);
}

if (result.invalidateOnFileChange) {
invalidateOnFileChange.push(...result.invalidateOnFileChange);
}

if (result.isExcluded) {
return null;
return {
assetGroup: null,
invalidateOnFileCreate,
invalidateOnFileChange,
};
}

if (result.filePath != null) {
Expand Down Expand Up @@ -278,8 +310,8 @@ export class ResolverRunner {
: result.pipeline,
isURL: dep.specifierType === 'url',
},
invalidateOnFileCreate: result.invalidateOnFileCreate,
invalidateOnFileChange: result.invalidateOnFileChange,
invalidateOnFileCreate,
invalidateOnFileChange,
};
}

Expand Down Expand Up @@ -311,7 +343,11 @@ export class ResolverRunner {
}

if (dep.isOptional) {
return null;
return {
assetGroup: null,
invalidateOnFileCreate,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😁

invalidateOnFileChange,
};
}

let resolveFrom = dependency.resolveFrom ?? dependency.sourcePath;
Expand All @@ -320,19 +356,20 @@ export class ResolverRunner {
? normalizePath(fromProjectPathRelative(resolveFrom))
: '';

// $FlowFixMe because of the err.code assignment
let err = await this.getThrowableDiagnostic(
let diagnostic = await this.getDiagnostic(
dependency,
md`Failed to resolve '${dependency.specifier}' ${
dir ? `from '${dir}'` : ''
}`,
);

// Merge diagnostics
err.diagnostics.push(...diagnostics);
// $FlowFixMe[prop-missing]
err.code = 'MODULE_NOT_FOUND';
diagnostics.unshift(diagnostic);

throw err;
return {
assetGroup: null,
invalidateOnFileCreate,
invalidateOnFileChange,
diagnostics,
};
}
}
4 changes: 2 additions & 2 deletions packages/core/integration-tests/test/javascript.js
Original file line number Diff line number Diff line change
Expand Up @@ -2037,7 +2037,7 @@ describe('javascript', function() {
let output = await run(b);
assert(/^http:\/\/localhost\/test\.[0-9a-f]+\.txt$/.test(output.default));
let stats = await outputFS.stat(
path.join(distDir, url.parse(output.default).pathname),
path.join(distDir, output.default.pathname),
);
assert.equal(stats.size, 9);
});
Expand All @@ -2064,7 +2064,7 @@ describe('javascript', function() {
let output = await run(b);
assert(/^http:\/\/localhost\/test\.[0-9a-f]+\.txt$/.test(output.default));
let stats = await outputFS.stat(
path.join(distDir, url.parse(output.default).pathname),
path.join(distDir, output.default.pathname),
);
assert.equal(stats.size, 9);
});
Expand Down
26 changes: 26 additions & 0 deletions packages/core/integration-tests/test/watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -445,4 +445,30 @@ describe('watcher', function() {
},
]);
});

it('should rebuild if a missing file is added', async function() {
await outputFS.mkdirp(inputDir);
await outputFS.writeFile(
path.join(inputDir, '/index.js'),
'import {other} from "./other";\nexport default other;',
'utf8',
);

let b = bundler(path.join(inputDir, 'index.js'), {inputFS: overlayFS});
subscription = await b.watch();
let buildEvent = await getNextBuild(b);
assert.equal(buildEvent.type, 'buildFailure');

await outputFS.writeFile(
path.join(inputDir, '/other.js'),
'export const other = 2;',
'utf8',
);

buildEvent = await getNextBuild(b);
assert.equal(buildEvent.type, 'buildSuccess');

let res = await run(buildEvent.bundleGraph);
assert.equal(res.default, 2);
});
});
11 changes: 4 additions & 7 deletions packages/runtimes/hmr/src/loaders/hmr-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,12 @@ if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
let assets = data.assets.filter(asset => asset.envHash === HMR_ENV_HASH);

// Handle HMR Update
var handled = false;
assets.forEach(asset => {
var didAccept =
let handled = assets.every(asset => {
return (
asset.type === 'css' ||
(asset.type === 'js' &&
hmrAcceptCheck(module.bundle.root, asset.id, asset.depsByBundle));
if (didAccept) {
handled = true;
}
hmrAcceptCheck(module.bundle.root, asset.id, asset.depsByBundle))
);
});

if (handled) {
Expand Down
18 changes: 17 additions & 1 deletion packages/transformers/js/core/src/dependency_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -705,12 +705,28 @@ impl<'a> Fold for DependencyCollector<'a> {
use ast::*;

if let Some((specifier, span)) = self.match_import_meta_url(&node, self.decls) {
return self.add_url_dependency(
let url = self.add_url_dependency(
specifier.clone(),
span,
DependencyKind::URL,
self.config.source_type,
);

// If this is a library, we will already have a URL object. Otherwise, we need to
// construct one from the string returned by the JSRuntime.
if !self.config.is_library {
return Expr::New(NewExpr {
span: DUMMY_SP,
callee: Box::new(Expr::Ident(Ident::new(js_word!("URL"), DUMMY_SP))),
args: Some(vec![ExprOrSpread {
expr: Box::new(url),
spread: None,
}]),
type_args: None,
});
}

return url;
}

let is_require = match &node {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ function shouldExclude(asset, options) {
asset.env.isWorker() ||
asset.env.isWorklet() ||
options.mode !== 'development' ||
!asset.getDependencies().find(v => v.specifier === 'react')
!asset
.getDependencies()
.find(v => v.specifier === 'react' || v.specifier === 'react/jsx-runtime')
);
}

Expand Down