Vibe SharePoint is a SharePoint Framework 1.22.x React web part that turns a SharePoint page into a full-screen single page application host.
The concept is documented in docs/sharepoint-spa-hosting-idea.md: SharePoint Online as a Vercel-like host for enterprise and government internal apps, with Microsoft 365 identity, permissions, lists, libraries, workflow, audit, and governance already in the platform.
Replace these placeholders with your tenant's values before deploying:
Tenant domain: <tenant>.sharepoint.com
Tenant ID: <M365_TENANT_ID>
Target site: https://<tenant>.sharepoint.com/sites/<site-path>
Home page: SitePages/Vibe.aspx
Site app catalog: https://<tenant>.sharepoint.com/sites/<site-path>/AppCatalog
SPFx package: sharepoint/solution/vibe-sharepoint.sppkg
Web part ID: 47458663-8ac5-44bc-aa56-21549e8a3f66
Solution ID: 2fb00bd1-df86-4a7d-9eb5-bd1b4ce60636
Deploy app/client ID: <M365_APP_ID>
Deploy app display name: Vibe SharePoint CLI
To deploy to another site or tenant, update the workflow SITE_URL, create or reuse an Entra app registration in that tenant, and replace the GitHub secrets.
- Node.js 22 LTS.
- npm.
- SharePoint Online site where the app should be hosted.
- SharePoint Administrator or Global Administrator for one-time setup.
- CLI for Microsoft 365 for local deployment and tenant setup:
npm install --global @pnp/cli-microsoft365This project uses SPFx 1.22.x and the Heft toolchain. The repo pins Node expectations with .nvmrc and .npmrc.
git clone https://github.com/<your-account>/vibe-sharepoint-template.git
cd vibe-sharepoint-template
npm ci
npm run buildThe deployable package is created at:
sharepoint/solution/vibe-sharepoint.sppkg
Trust the localhost certificate once:
npm run trust-dev-certPoint the hosted workbench at your tenant and start SPFx:
$env:SPFX_SERVE_TENANT_DOMAIN = "<tenant>.sharepoint.com"
npm run startHosted workbench URL pattern:
https://<tenant>.sharepoint.com/_layouts/workbench.aspx?debugManifestsFile=https%3A%2F%2Flocalhost%3A4321%2Ftemp%2Fbuild%2Fmanifests.js&debug=true&noredir=true
The deployment identity is an Entra app registration with certificate authentication.
After running the setup, you will end up with values shaped like:
M365_APP_ID = <your app registration client ID>
Display name = Vibe SharePoint CLI
Certificate thumbprint = <your certificate thumbprint>
Certificate expiry = <your certificate expiry>
Create the tenant-local app registration and certificate. A working local pattern is:
$app = az ad app create `
--display-name "Vibe SharePoint CLI" `
--sign-in-audience AzureADMyOrg `
--is-fallback-public-client true `
--public-client-redirect-uris "http://localhost" `
--query "{appId:appId,id:id}" `
-o json | ConvertFrom-Json
$appId = $app.appIdCreate a certificate and export GitHub secret values:
$certDir = ".local\certs"
New-Item -ItemType Directory -Force -Path $certDir | Out-Null
$cert = New-SelfSignedCertificate `
-Subject "CN=Vibe SharePoint GitHub Deploy" `
-CertStoreLocation "Cert:\CurrentUser\My" `
-KeyExportPolicy Exportable `
-KeySpec Signature `
-KeyLength 2048 `
-KeyAlgorithm RSA `
-HashAlgorithm SHA256 `
-NotAfter (Get-Date).AddYears(2) `
-FriendlyName "Vibe SharePoint GitHub Deploy"
$passwordPlain = -join ((48..57 + 65..90 + 97..122) | Get-Random -Count 40 | ForEach-Object {[char]$_})
$password = ConvertTo-SecureString -String $passwordPlain -Force -AsPlainText
Export-Certificate -Cert $cert -FilePath "$certDir\vibe-sharepoint-gh-deploy.cer" | Out-Null
Export-PfxCertificate -Cert $cert -FilePath "$certDir\vibe-sharepoint-gh-deploy.pfx" -Password $password | Out-Null
[Convert]::ToBase64String([IO.File]::ReadAllBytes("$certDir\vibe-sharepoint-gh-deploy.pfx")) |
Set-Content "$certDir\M365_CERTIFICATE_ENCODED.txt" -NoNewline
$passwordPlain | Set-Content "$certDir\M365_CERTIFICATE_PASSWORD.txt" -NoNewlineAttach the public certificate to the app registration:
az ad app credential reset `
--id $appId `
--cert "@.local\certs\vibe-sharepoint-gh-deploy.cer" `
--append `
--display-name "GitHub Actions SPFx Deploy" `
--years 2The deployment app needs:
- Microsoft Graph application permission:
Sites.Read.All. - SharePoint application permissions sufficient for app catalog upload/deploy. This tenant uses SharePoint app roles including
Sites.ReadWrite.All,Sites.Manage.All, andSites.FullControl.All. - Site app permission
fullcontrolon the target site collection app catalog site.
Common IDs you will need to look up in your tenant:
Microsoft Graph resource app ID: 00000003-0000-0000-c000-000000000000
Graph Sites.Read.All app role ID: 332a536c-c7ef-4017-ab91-336970924f0d
SharePoint resource app ID: 00000003-0000-0ff1-ce00-000000000000
SharePoint Sites.ReadWrite.All app role ID: fbcd29d2-fcca-4405-aded-518d457caae4
SharePoint Sites.Manage.All app role ID: 9bff6588-13f2-4c48-bbf2-ddab62256b36
SharePoint Sites.FullControl.All app role ID: 678536fe-1083-478a-9c59-b99265e6b0d3
Query these IDs in your tenant rather than copying values:
az ad sp show --id 00000003-0000-0000-c000-000000000000 `
--query "appRoles[?value=='Sites.Read.All'].{value:value,id:id}" -o table
az ad sp show --id 00000003-0000-0ff1-ce00-000000000000 `
--query "appRoles[?value=='Sites.ReadWrite.All' || value=='Sites.Manage.All' || value=='Sites.FullControl.All'].{value:value,id:id}" -o tableAfter adding app roles to the app registration, make sure the service principal actually has the role assignments. The workflow depends on certificate/app-only auth, not delegated user auth.
This project deploys to the site collection app catalog for the target site instead of the tenant app catalog.
Check whether the site catalog exists:
m365 spo site appcatalog list -o jsonCreate it when missing:
m365 spo site appcatalog add --siteUrl "https://<tenant>.sharepoint.com/sites/<site-path>"Grant the deployment app full control on the site collection app catalog:
m365 spo site apppermission add `
--siteUrl "https://<tenant>.sharepoint.com/sites/<site-path>" `
--permission fullcontrol `
--appId "<M365_APP_ID>" `
--appDisplayName "Vibe SharePoint CLI"This grant must be run from a delegated admin login, not the certificate app-only login.
Login interactively for setup or troubleshooting:
m365 login `
--authType deviceCode `
--appId "<M365_APP_ID>" `
--tenant "<M365_TENANT_ID>"Login non-interactively with the certificate:
$tenantId = "<M365_TENANT_ID>"
$appId = "<M365_APP_ID>"
$certBase64 = Get-Content .local\certs\M365_CERTIFICATE_ENCODED.txt -Raw
$certPassword = Get-Content .local\certs\M365_CERTIFICATE_PASSWORD.txt -Raw
m365 login `
--authType certificate `
--tenant $tenantId `
--appId $appId `
--certificateBase64Encoded $certBase64 `
--password $certPasswordBuild, upload, and deploy to the site app catalog:
npm run clean
npm run build
m365 spo app add `
--filePath "sharepoint/solution/vibe-sharepoint.sppkg" `
--appCatalogScope sitecollection `
--appCatalogUrl "https://<tenant>.sharepoint.com/sites/<site-path>" `
--overwrite
m365 spo app deploy `
--name "vibe-sharepoint.sppkg" `
--appCatalogScope sitecollection `
--appCatalogUrl "https://<tenant>.sharepoint.com/sites/<site-path>" `
--skipFeatureDeploymentThe target host page is:
SitePages/Vibe.aspx
Create the page if missing:
m365 spo page add `
--webUrl "https://<tenant>.sharepoint.com/sites/<site-path>" `
--name "Vibe.aspx" `
--title "Vibe" `
--layoutType SingleWebPartAppPageSet or repair the page layout:
m365 spo page set `
--webUrl "https://<tenant>.sharepoint.com/sites/<site-path>" `
--name "Vibe.aspx" `
--layoutType SingleWebPartAppPage `
--title "Vibe"Add the web part if it is missing:
m365 spo page section add `
--webUrl "https://<tenant>.sharepoint.com/sites/<site-path>" `
--pageName "Vibe.aspx" `
--sectionTemplate OneColumnFullWidth `
--order 1
m365 spo page clientsidewebpart add `
--webUrl "https://<tenant>.sharepoint.com/sites/<site-path>" `
--pageName "Vibe.aspx" `
--webPartId "47458663-8ac5-44bc-aa56-21549e8a3f66" `
--section 1 `
--column 1 `
--order 1Publish and make it the site home page:
m365 spo page set `
--webUrl "https://<tenant>.sharepoint.com/sites/<site-path>" `
--name "Vibe.aspx" `
--layoutType SingleWebPartAppPage `
--title "Vibe" `
--publish
m365 spo web set `
--url "https://<tenant>.sharepoint.com/sites/<site-path>" `
--welcomePage "SitePages/Vibe.aspx" `
--quickLaunchEnabled false `
--headerLayout compact `
--footerEnabled falseThe web part also injects page-level CSS to hide SharePoint chrome for an app-like experience:
#sp-appBar,
#spCommandBar,
#spSiteHeader,
#SuiteNavWrapperThe workflow is .github/workflows/spfx-deploy.yml.
It performs:
1. Checkout
2. Setup Node 22
3. npm ci
4. npm run clean
5. npm run build
6. Install CLI for Microsoft 365
7. Certificate login
8. Ensure site collection app catalog exists
9. Upload .sppkg to the site app catalog
10. Deploy the package
11. Create or repair SitePages/Vibe.aspx
12. Add the web part if missing
13. Publish the page
14. Set Vibe.aspx as the site home page
15. Verify package, page, and site settings
Set these repository secrets:
M365_TENANT_ID
M365_APP_ID
M365_CERTIFICATE_ENCODED
M365_CERTIFICATE_PASSWORD
Read the local cert secret files with:
Get-Content .local\certs\M365_CERTIFICATE_ENCODED.txt -Raw
Get-Content .local\certs\M365_CERTIFICATE_PASSWORD.txt -RawDo not commit .local/; it is intentionally ignored.
Update these workflow values:
env:
SITE_URL: https://contoso.sharepoint.com/sites/new-site
PAGE_NAME: Vibe.aspx
PAGE_TITLE: VibeThen ensure the target site has:
- A site collection app catalog.
- Site app permission for the deployment app.
- The same SPFx package deployed to that site catalog.
For a new tenant:
- Create the SharePoint site.
- Create a tenant-local Entra app registration.
- Create and attach a certificate.
- Add/admin-consent Graph and SharePoint application roles.
- Create the site collection app catalog.
- Grant the app full control to the target site app catalog.
- Add GitHub repository secrets for that tenant.
- Update
SITE_URLin the workflow. - Run the workflow manually once.
m365 spo app get `
--name "vibe-sharepoint.sppkg" `
--appCatalogScope sitecollection `
--appCatalogUrl "https://<tenant>.sharepoint.com/sites/<site-path>"
m365 spo page get `
--webUrl "https://<tenant>.sharepoint.com/sites/<site-path>" `
--name "Vibe.aspx" `
--query "{Title:title,Layout:layoutType,Url:ServerRelativeUrl,Version:UIVersionLabel}" `
-o json
m365 spo web get `
--url "https://<tenant>.sharepoint.com/sites/<site-path>" `
--query "{WelcomePage:WelcomePage,QuickLaunchEnabled:QuickLaunchEnabled,FooterEnabled:FooterEnabled}" `
-o jsonExpected current result:
Package deployed: true
Page layout: SingleWebPartAppPage
Welcome page: SitePages/Vibe.aspx
Quick launch: false
Footer: false