Skip to content

Commit

Permalink
More bugs (#6567)
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett committed Jul 8, 2021
1 parent ed8d3e4 commit db75d9c
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 69 deletions.
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,
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
Loading

0 comments on commit db75d9c

Please sign in to comment.