-
-
Notifications
You must be signed in to change notification settings - Fork 653
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
Prefix path router #3592
base: main
Are you sure you want to change the base?
Prefix path router #3592
Changes from all commits
3e22a58
a6cf32e
a523fa7
30d2638
0be7e30
ab146ac
cb21196
4c35003
67452b7
c485e5f
9505e56
f2f908e
c284ec5
97f3f9c
f37a938
76f0f33
ed28182
57537bb
4a6f184
dfdd13f
e38bccc
cf7d2ae
3be3238
1ceb872
d6f8bab
7f435b0
aa7ef2b
30a9799
63c7858
035bc59
392bdfd
9af9eb8
e201fc3
3089740
7037193
1b4baa6
cc13733
88d8ed4
bbf84cb
3ad97df
6b3e876
b964d97
b8d8413
40e5379
db1fe08
ef6216a
21162d3
14de201
e8b3859
04dc8aa
ecd601d
0b5bff7
260cfcd
f3dd2b5
1c676ff
cfb5a73
000f503
76008a6
39c1e4a
22749f9
1b78ad5
fc56c8e
73a3dab
ca6004e
3f3e81f
ea9c14b
caae9ab
a06a91c
735090c
aa0c72b
3938b21
b07f431
3a10d4a
562e01e
c50341b
61d96d2
c793816
48554df
294a090
ad3a147
8d8edf3
9a6b25f
149c899
e32637b
5eddf39
8cf3b05
5ce2e94
a59a704
2944946
235e4c5
38e428c
1e2620e
f3a51a4
433ad1c
dd553b8
d66b0ac
a38dda0
0afb5c7
b220146
699dfb1
e8b69cf
d1263ee
c2ae5a4
223cf17
0d357e1
453bdbc
7efbd7f
9e4712e
06f3e1f
e6ea8aa
2b59a49
3856b7c
5e90e60
e8889fe
ccc0b0e
01148eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,4 +18,5 @@ seamless-mode | |
apache | ||
sentry | ||
performance | ||
prefixed-root | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
--- | ||
myst: | ||
html_meta: | ||
"description": "Prefixed (non-root) deployment for Volto" | ||
"property=og:description": "Prefixed (non-root) deployment for Volto" | ||
"property=og:title": "Prefixed (non-root) deployment" | ||
"keywords": "Volto, deployment" | ||
--- | ||
|
||
# Prefixed (non-root) deployment | ||
|
||
If you're integrating a Volto website within another existing website, you may need to run Volto on a virtual path inside that website instead of the root path. | ||
|
||
The first step is to set an environment variable `RAZZLE_PREFIX_PATH` to the prefixed path of your Volto. | ||
For example, if you want Volto's root to be hosted at `http://example.com/my-prefix`, you need to start Volto with: | ||
|
||
```shell | ||
RAZZLE_PREFIX_PATH=/my-prefix yarn start | ||
``` | ||
|
||
If you need to debug and understand how the requests are rewritten by the Volto SSR, you can add the following environment variables to the Volto start line: | ||
|
||
|
||
```shell | ||
DEBUG_HPM=true DEBUG=superagent RAZZLE_PREFIX_PATH=/my-prefix yarn start | ||
``` | ||
|
||
The prefix location will be used regardless of how you start Volto, whether in development or production mode. | ||
When developing, though, if your backend is something other then `http://localhost:8080`, you'll need to provide your own solution for how to handle things. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So in development I don't have to set it up and act as I'm in the root then? |
||
|
||
For a production setup, when hosting Volto behind a proxy HTTP server, you can configure your rewrite rules to something like the following, in this case for Apache. | ||
|
||
```apache | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The recommended deployment setup is using Docker. I know that the documentation about this is in a sorry state, but we cannot add more confusion about this by dropping an In the upcoming sprints we should work on documenting properly the deployment story. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sneridagh would it be an idea to use an example with |
||
RewriteRule ^/level-1/\+\+api\+\+(.*) http://plone:8080/VirtualHostBase/http/example.com:80/Plone/VirtualHostRoot/_vh_level-1$1 [P,L] | ||
RewriteRule ^/level-1(.*) http://volto:3000/level-1$1 [P,L] | ||
``` | ||
|
||
In case you have a deeper prefix path (for example, `/level1/level2`), you can do the following. | ||
Notice the multiple `_vh_` segments in the rewrite rule. | ||
|
||
```apache | ||
RewriteRule ^/level-1/level-2/\+\+api\+\+(.*) http://plone:8080/VirtualHostBase/http/example.com:80/Plone/VirtualHostRoot/_vh_level-1/_vh_level-2$1 [P,L] | ||
RewriteRule ^/level-1/level-2(.*) http://volto:3000/level-1/level-2$1 [P,L] | ||
``` | ||
|
||
And start Volto with the following. | ||
|
||
```shell | ||
RAZZLE_PREFIX_PATH=/level1/level2 RAZZLE_API_PATH=http://example.com/level1/level2 yarn start | ||
``` | ||
|
||
Note, as you'll be integrating Volto with an existing website, you need to configure `config.settings.externalRoutes` so that the router knows which routes it should consider internal. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need more elaboration and reasoning why this is necessary. |
||
|
||
Finally, because `RAZZLE_PREFIX_PATH` is also used to configure the location of the static resources in webpack, when you build the static resources bundle, you must use a command such as the following. | ||
|
||
```shell | ||
RAZZLE_PREFIX_PATH=/level1/level2 yarn build | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
added support for prefixPath. @giuliaghisini @cekk @pnicolli @mamico @nileshgulia1 @wesleybl |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
http: | ||
routers: | ||
frontend: | ||
rule: "Host(`localhost`) && PathPrefix(`/foo`)" | ||
service: frontend | ||
backend: | ||
rule: "Host(`localhost`) && PathPrefix(`/foo/++api++`)" | ||
service: backend | ||
middlewares: | ||
- backend | ||
|
||
middlewares: | ||
backend: | ||
replacePathRegex: | ||
regex: "^/foo/\\+\\+api\\+\\+($|/.*)" | ||
replacement: "/VirtualHostBase/http/localhost/plone/++api++/VirtualHostRoot/_vh_foo$1" | ||
|
||
services: | ||
frontend: | ||
loadBalancer: | ||
servers: | ||
- url: "http://host.docker.internal:3000" | ||
backend: | ||
loadBalancer: | ||
servers: | ||
- url: "http://host.docker.internal:55001" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
version: "3.7" | ||
|
||
services: | ||
|
||
proxy: | ||
image: traefik:v2.8 | ||
command: | ||
- "--api.insecure=true" | ||
- "--providers.docker=true" | ||
# - "--providers.docker.exposedbydefault=false" | ||
- "--providers.file=true" | ||
- "--providers.file.filename=/etc/traefik/rules.yml" | ||
- "--entrypoints.web.address=:80" | ||
- "--api.insecure=true" | ||
# - "--accesslog=true" | ||
# - "--log.level=DEBUG" | ||
ports: | ||
- 80:80 | ||
- "8888:8080" | ||
volumes: | ||
- /var/run/docker.sock:/var/run/docker.sock | ||
- ./prefixed-rules.yml:/etc/traefik/rules.yml | ||
extra_hosts: | ||
- host.docker.internal:host-gateway |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,11 @@ | ||
import { | ||
getIfExists, | ||
getTextNode, | ||
setBaseAndExtent, | ||
createHtmlPasteEvent, | ||
} from '../helpers'; | ||
/* eslint-disable no-console */ | ||
import '@testing-library/cypress/add-commands'; | ||
import { getIfExists } from '../helpers'; | ||
import { ploneAuth } from './constants'; | ||
|
||
const HOSTNAME = Cypress.env('BACKEND_HOST') || '127.0.0.1'; | ||
|
@@ -841,38 +846,14 @@ Cypress.Commands.add('clickSlateButton', (button, timeout = 1000) => { | |
}).click({ force: true }); // force click is needed to ensure the button in visible in view. | ||
}); | ||
|
||
// Helper functions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 I started this already in a recent PR. A merge might be needed. |
||
function getTextNode(el, match) { | ||
const walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false); | ||
if (!match) { | ||
return walk.nextNode(); | ||
} | ||
|
||
let node; | ||
while ((node = walk.nextNode())) { | ||
if (node.wholeText.includes(match)) { | ||
return node; | ||
} | ||
} | ||
} | ||
|
||
function setBaseAndExtent(...args) { | ||
const document = args[0].ownerDocument; | ||
document.getSelection().removeAllRanges(); | ||
document.getSelection().setBaseAndExtent(...args); | ||
} | ||
|
||
function createHtmlPasteEvent(htmlContent) { | ||
return Object.assign( | ||
new Event('paste', { bubbles: true, cancelable: true }), | ||
{ | ||
clipboardData: { | ||
getData: () => htmlContent, | ||
types: ['text/html'], | ||
}, | ||
}, | ||
); | ||
} | ||
/* add prefixPath from Cypress.env to supplied path | ||
* designed for CI only | ||
* for local, add prefixPath to Cypress.env | ||
*/ | ||
Cypress.Commands.add('addBaseUrl', (url) => { | ||
const prefixPath = Cypress.env('prefixPath'); | ||
return prefixPath ? prefixPath + url : url; | ||
}); | ||
|
||
Cypress.Commands.add('addNewBlock', (blockName, createNewSlate = false) => { | ||
let block; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
describe('actions Tests', () => { | ||
let prefixPath; | ||
beforeEach(() => { | ||
cy.autologin(); | ||
cy.createContent({ | ||
|
@@ -8,6 +9,7 @@ describe('actions Tests', () => { | |
allow_discussion: true, | ||
}); | ||
cy.visit('/contents'); | ||
prefixPath = Cypress.env('prefixPath') || ''; | ||
}); | ||
it('copy', function () { | ||
cy.get('tr[aria-label="/my-page-1"]').within(() => { | ||
|
@@ -20,7 +22,7 @@ describe('actions Tests', () => { | |
cy.get('a[class="icon-align-name"]').should( | ||
'have.attr', | ||
'href', | ||
'/copy_of_my-page-1/contents', | ||
`${prefixPath}/copy_of_my-page-1/contents`, | ||
); | ||
}); | ||
}); | ||
|
@@ -44,7 +46,7 @@ describe('actions Tests', () => { | |
cy.get('a[class="icon-align-name"]').should( | ||
'have.attr', | ||
'href', | ||
'/my-page-1/contents', | ||
`${prefixPath}/my-page-1/contents`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't we do it more elegant by invoking the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sneridagh yes would be. And it would be less code to change. When I have time I will change this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sneridagh I started looking into this but that won't be possible.
But links in HTML are relative. For example:
|
||
); | ||
}); | ||
}); | ||
|
@@ -62,7 +64,7 @@ describe('actions Tests', () => { | |
cy.get('a[class="icon-align-name"]').should( | ||
'have.attr', | ||
'href', | ||
'/my-page-rename/contents', | ||
`${prefixPath}/my-page-rename/contents`, | ||
); | ||
}); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this page needs to have better narrative structure, such as the following: