-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add CSP-friendly Alpine build (#3959)
* refactor csp build * document
- Loading branch information
1 parent
b24d8be
commit 8c1511a
Showing
5 changed files
with
144 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { generateEvaluatorFromFunction, runIfTypeOfFunction } from 'alpinejs/src/evaluator' | ||
import { closestDataStack, mergeProxies } from 'alpinejs/src/scope' | ||
import { tryCatch } from 'alpinejs/src/utils/error' | ||
import { injectMagics } from 'alpinejs/src/magics' | ||
|
||
export function cspEvaluator(el, expression) { | ||
let dataStack = generateDataStack(el) | ||
|
||
// Return if the provided expression is already a function... | ||
if (typeof expression === 'function') { | ||
return generateEvaluatorFromFunction(dataStack, expression) | ||
} | ||
|
||
let evaluator = generateEvaluator(el, expression, dataStack) | ||
|
||
return tryCatch.bind(null, el, expression, evaluator) | ||
} | ||
|
||
function generateDataStack(el) { | ||
let overriddenMagics = {} | ||
|
||
injectMagics(overriddenMagics, el) | ||
|
||
return [overriddenMagics, ...closestDataStack(el)] | ||
} | ||
|
||
function generateEvaluator(el, expression, dataStack) { | ||
return (receiver = () => {}, { scope = {}, params = [] } = {}) => { | ||
let completeScope = mergeProxies([scope, ...dataStack]) | ||
|
||
if (completeScope[expression] === undefined) { | ||
throwExpressionError(el, expression) | ||
} | ||
|
||
runIfTypeOfFunction(receiver, completeScope[expression], completeScope, params) | ||
} | ||
} | ||
|
||
function throwExpressionError(el, expression) { | ||
console.warn( | ||
`Alpine Error: Alpine is unable to interpret the following expression using the CSP-friendly build: | ||
"${expression}" | ||
Read more about the Alpine's CSP-friendly build restrictions here: https://alpinejs.dev/advanced/csp | ||
`, | ||
el | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,37 @@ | ||
/** | ||
* Alpine CSP Build. | ||
* | ||
* Alpine allows you to use JavaScript directly inside your HTML. This is an | ||
* incredibly powerful features. However, it violates the "unsafe-eval" | ||
* Content Security Policy. This alternate Alpine build provides a | ||
* more constrained API for Alpine that is also CSP-friendly... | ||
*/ | ||
import Alpine from 'alpinejs/src/alpine' | ||
|
||
Alpine.setEvaluator(cspCompliantEvaluator) | ||
|
||
/** | ||
* _______________________________________________________ | ||
* The Evaluator | ||
* ------------------------------------------------------- | ||
* | ||
* By default, Alpine's evaluator "eval"-like utilties to | ||
* interpret strings as runtime JS. We're going to use | ||
* a more CSP-friendly evaluator for this instead. | ||
*/ | ||
import { cspEvaluator } from './evaluator' | ||
|
||
Alpine.setEvaluator(cspEvaluator) | ||
|
||
/** | ||
* The rest of this file bootstraps Alpine the way it is | ||
* normally bootstrapped in the default build. We will | ||
* set and define it's directives, magics, etc... | ||
*/ | ||
import { reactive, effect, stop, toRaw } from '@vue/reactivity' | ||
|
||
Alpine.setReactivityEngine({ reactive, effect, release: stop, raw: toRaw }) | ||
|
||
import 'alpinejs/src/magics/index' | ||
import 'alpinejs/src/directives/index' | ||
|
||
import { closestDataStack, mergeProxies } from 'alpinejs/src/scope' | ||
import { injectMagics } from 'alpinejs/src/magics' | ||
import { generateEvaluatorFromFunction, runIfTypeOfFunction } from 'alpinejs/src/evaluator' | ||
import { tryCatch } from 'alpinejs/src/utils/error' | ||
|
||
function cspCompliantEvaluator(el, expression) { | ||
let overriddenMagics = {} | ||
|
||
injectMagics(overriddenMagics, el) | ||
|
||
let dataStack = [overriddenMagics, ...closestDataStack(el)] | ||
|
||
if (typeof expression === 'function') { | ||
return generateEvaluatorFromFunction(dataStack, expression) | ||
} | ||
|
||
let evaluator = (receiver = () => {}, { scope = {}, params = [] } = {}) => { | ||
let completeScope = mergeProxies([scope, ...dataStack]) | ||
|
||
if (completeScope[expression] !== undefined) { | ||
runIfTypeOfFunction(receiver, completeScope[expression], completeScope, params) | ||
} | ||
} | ||
|
||
return tryCatch.bind(null, el, expression, evaluator) | ||
} | ||
import 'alpinejs/src/directives/index' | ||
|
||
export default Alpine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
--- | ||
order: 1 | ||
order: 2 | ||
title: Reactivity | ||
--- | ||
|
||
|