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

Add support for publishing to Custom domains #982

Merged
merged 4 commits into from
May 18, 2022

Conversation

matthewdavidrodgers
Copy link
Contributor

With the release of Custom Domains for workers, users can publish directly to a custom domain on a route, rather than creating a dummy DNS record first and manually pointing the worker over - this adds the same support to wrangler.

Users declare routes as normal, but to indicate that a route should be treated as a custom domain, a user simply uses the object format in the toml file, but with a new key: custom_domain (i.e. routes = [{ pattern = "api.example.com", custom_domain = true }])

When wrangler sees a route like this, it peels them off from the rest of the routes and publishes them separately, using the /domains api. This api is very defensive, erroring eagerly if there are conflicts in existing Custom Domains or managed DNS records. In the case of conflicts, wrangler prompts for confirmation, and then retries with parameters to indicate overriding is allowed.

@changeset-bot
Copy link

changeset-bot bot commented May 12, 2022

🦋 Changeset detected

Latest commit: 6a8f041

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
wrangler Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Comment on lines +78 to +88
function getQuoteBoundedSubstring(content: string) {
const matches = content.split('"');
return matches[1] ?? "";
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Originally tried to use a regex here, but it was too permissive when there were multiple quote bounded substrings. This will always grab the first one (and even works when the string begins with a quote)

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any time when the substring might contain an escaped quote?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

there's no current situation where this could occur - I authored the code that generates these messages - but I suppose all bets are off if the code drifts. I could add a comment reinforcing the general structure in the api

@Electroid Electroid self-requested a review May 13, 2022 02:44
Copy link
Contributor

@Electroid Electroid left a comment

Choose a reason for hiding this comment

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

Maybe @threepointone would have a good opinion on this, but I wonder if it makes sense for this feature to be separate from routes, something like:

domains = ["api.example.com"]

The reason I propose this is because I think we want to push folks to use domains instead of routes, since it sets up DNS, SSL, and all that jazz. If we jam them together, it might get confusing.

@github-actions
Copy link
Contributor

github-actions bot commented May 13, 2022

A wrangler prerelease is available for testing. You can install this latest build in your project with:

npm install --save-dev https://prerelease-registry.developers.workers.dev/runs/2342037445/npm-package-wrangler-982

You can reference the automatically updated head of this PR with:

npm install --save-dev https://prerelease-registry.developers.workers.dev/prs/982/npm-package-wrangler-982

Or you can use npx with this latest build directly:

npx https://prerelease-registry.developers.workers.dev/runs/2342037445/npm-package-wrangler-982 dev path/to/script.js

@threepointone
Copy link
Contributor

Another option is to use { domain = 'api.example.com' } as the form.

Thanks a lot for the PR @matthewdavidrodgers! This looks extensive, and thank you for adding tests! We'll review this soon.

Copy link
Contributor

@threepointone threepointone left a comment

Choose a reason for hiding this comment

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

Love this PR. I honestly don't have any notes, but I'll let @petebacondarwin have a quick look at this before I stamp it. Could you also rebase to head? We've landed a few changes since this came in.

packages/wrangler/src/publish.ts Outdated Show resolved Hide resolved
packages/wrangler/src/publish.ts Show resolved Hide resolved
Copy link
Contributor

@petebacondarwin petebacondarwin left a comment

Choose a reason for hiding this comment

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

Also love this PR. Made a few comments but none blocking merging this.
Thanks @matthewdavidrodgers.

packages/wrangler/src/config/environment.ts Outdated Show resolved Hide resolved
packages/wrangler/src/publish.ts Outdated Show resolved Hide resolved
packages/wrangler/src/publish.ts Outdated Show resolved Hide resolved
Comment on lines +78 to +88
function getQuoteBoundedSubstring(content: string) {
const matches = content.split('"');
return matches[1] ?? "";
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any time when the substring might contain an escaped quote?

Comment on lines +74 to +84
// this is useful because the /domains api will return
// which domains conflicted in an error message, bounded
// by a string, which we can use to provide helpful
// messages to a user
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be better to change the CF API so that it returned a structured response that we could parse more reliably?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so, went to the api team today to try and see what ways we can provide structured data in an error response, and there weren't a whole lot of options they felt would work. something simple and trivially parseable within the error message seems to be the best way to handle this.

currently, the error messages look something like this:
Cannot create Custom Domain "<domain>": Custom Domain already exists and points to a different script; retry and use option "override_existing_origin" to override
which is why I parse out the first quote bounded substring.

do we feel better if i change the error message to look something like this:
"<domain>" could not be created as a Custom Domain; already exists and points to a different script; retry and use option "override_existing_origin" to override
so at least the conflicting domains are the first thing in the message? maybe making the parsing less fraught?

@Electroid
Copy link
Contributor

Electroid commented May 17, 2022

I think @threepointone’s idea of routes = [{domain = “api.example.com”] is worth considering here. It’s compact and more succinct than having a separate boolean. It’s also not really a “pattern”

@matthewdavidrodgers
Copy link
Contributor Author

I think @threepointone’s idea of routes = [{domain = “api.example.com”] is worth considering here. It’s compact and more succinct than having a separate boolean. It’s also not really a “pattern”

I went with the custom_domain boolean because it's likely we will have support for something like wildcard operators in custom domains in the future, and "pattern" will actually fit well. As for the point around a separate top level key in the toml (i.e. domains = [...] vs routes = [...]), I felt that having to pick between the two would be confusing for a first time user, and wanted to keep an easy default. But if that doesn't fit how we're thinking about this, I'm sure it can change

Needed to re-write a "renderer" of the route to be logged out to the
user, but it's now supported in the type system
If a toml provides routes with the "custom_domain" flag, publish those
separately from normal routes, using the /domains api. As these are more
complex than simple routes, we ask the api to error eagerly. If it
errors on a conflict for existing custom domains or managed DNS records,
we prompt for confirmation to override the conflicts, and then retry
with updated parameters
Copy link
Contributor

@threepointone threepointone left a comment

Choose a reason for hiding this comment

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

Ok, I'm ready to land this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants