Relax script-src and worker-src to 'self' so Code Apps can use code-splitting and Web Workers #368
Craig-Humphrey
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
[Apologies for the AI created content, but Claude and I have been working on this together]
Summary
The CSP applied to deployed Code Apps currently forces every line of JS into a single monolithic bundle and forbids Web Workers entirely. As Code Apps grow beyond simple data-entry forms, this is becoming a real ceiling on what's practical to build. Two small CSP relaxations - both to
'self'only, no third-party origins - would unlock standard React/Vite patterns (React.lazy, route-based code-splitting, Web Workers) without weakening the security posture.The constraints today
When
npx power-apps pushdeploys a Code App, the served page enforces (relevant directives only):script-src'self'for dynamic scripts)<script>injection - i.e.React.lazy(),import(),manualChunksworker-src'none'new Worker(url),new Worker(blobUrl), Service Workers, Shared Workersframe-src'self'plus a fixed listblob:URLs in iframes (e.g. PDF preview via<iframe src=blobUrl>)connect-srcThe first two are the painful ones for bundle size and library compatibility.
Concrete case: pdf.js in a real app
We're building a vehicle-leasing Code App (React 19 + Vite 7 + Fluent UI v9) that needs to render PDFs (vehicle fitout specs uploaded to Dataverse). pdf.js is the standard choice. None of the documented integration paths work under the current CSP:
new pdfjsLib.GlobalWorkerOptions.workerSrc = '/pdf.worker.js'thennew Worker(url)- blocked byworker-src 'none'?rawimport + blob URL Worker - blob: also blocked byworker-src 'none'workerSrc = ''(run on main thread officially) - pdf.js v5 throwsNo GlobalWorkerOptions.workerSrc specifiedimport()fallback from the pdf.js library itself - blocked byscript-srcThe only thing that works is a static ES module import of the worker file so Vite inlines it into the main bundle:
pdf.js detects
globalThis.pdfjsWorkerand falls back to aLoopbackPortthat runs everything on the main thread. Cost: ~1.5 MB added to the main bundle, plus no worker isolation = main thread blocked while rendering pages.Our app's current
dist/assets/index-*.jsis 2.37 MB minified (≈700 KB gzipped). Vite's default 500 KB warning fires on every build. The app still runs fine, but:What we tried (and why each was a dead-end)
vite-plugin-pwato push the worker to a Service Workerworker-src 'none'blocks itReact.lazy(() => import('./pages/LeaseDetail'))with route-based splittingimport()which compiles to a runtime<script>injectionbuild.rollupOptions.output.manualChunksto split vendor bundlesformat: 'iife')Function()/eval()assetsInlineLimitcranked up for images (per workaround in #316)The fundamental issue: Rollup's code-splitting, React.lazy, and Web Workers all depend on the browser being allowed to load additional JS from
'self'after page load. The CSP forbids exactly that.Proposed changes
Two minimal relaxations, both same-origin only:
1.
script-srcshould allow'self'for additional chunksThe Vite build output is uploaded to the same
*.powerplatformusercontent.comorigin as the main HTML. Allowing'self'forscript-srclets the browser load Rollup-generated chunk files, which unlocks:React.lazy()for route-based code-splittingimport()for on-demand library loading (e.g. only load pdf.js when a PDF is actually shown)manualChunksfor vendor/framework separation and better cache hit ratesSecurity impact: minimal. Same-origin scripts are already trusted - the main bundle is loaded from
'self'today.2.
worker-srcshould allow'self'(andblob:if practical)This lets standard libraries use Web Workers as designed:
Security impact: minimal. Workers run in their own context and have no DOM access; allowing same-origin workers is industry standard.
Alternative / interim option
If the above is too big a change, even a per-app opt-in in
power.config.jsonwould be valuable:{ "csp": { "allowSelfScripts": true, // enable code-splitting "allowSelfWorkers": true // enable Web Workers } }Makers who want the stricter default get it; makers who need bundle-size relief or worker libraries can opt in knowingly.
Why this is worth doing now
Code Apps GA'd in late 2025. Most apps in flight today are small enough not to hit the 500 KB threshold yet, which is probably why this hasn't been raised before - I checked existing issues/discussions and found nothing on
lazy,chunk,code split,dynamic import, orbundle size(only #316, which is the related binary-asset CLI bug with the sameassetsInlineLimitworkaround). But:assetsInlineLimit) doesn't scale, as @eschavez confirmed in [Bug] Static binary assets (images) corrupted by storageproxy after deployment #316worker-srcrelaxationRelated
assetsInlineLimitworkaround)worker-src 'none')Happy to provide a minimal reproducible Code App showing the React.lazy / pdf.js / Worker failures under the current CSP if that would help.
Beta Was this translation helpful? Give feedback.
All reactions