Casper Context is a Babel compile-time plugin that transforms specially prefixed variables into fully functional React Context API state β automatically.
No providers. No boilerplate. No complex setup.
Just declare β use β update.
import React from 'react'
function App() {
let _$_appMessage = 'Say Hi to the Casper';
return (
<>
<CasperHero />
<MessageBox />
</>
);
}import React from 'react'
function CasperHero() {
return <h1>{_$_appMessage}</h1>;
}import React from 'react';
function MessageBox() {
const handleChange = () => {
_$_appMessage = 'Hi Casper';
}
return (
<>
<button onClick={handleChange}>
Change
</button>
</>;
}Thatβs it. Under the hood, the plugin rewrites your code to use the native React Context API. It is 100% React-compliant at runtime.
- Zero Boilerplate: No more createContext, useContext, or wrapping components manually.
- Automatic Reactivity: When a casper variable changes, all components using it re-render automatically..
- Scoped & Global: Accessible in the component where it's declared and any nested child component.
- Native Performance: Since it compiles to the native React Context API, there is zero overhead compared to writing Context manually.
- Standard Syntax: Use familiar assignment syntax to update global state.
npm install casper-context --save-devAdd it to your .babelrc or babel.config.js
{
"plugins": ["casper-context"]
}Create React App does not support direct Babel modification. You must use CRACO.
Install CRACO:
npm install @craco/cracoThen configure CRACO to inject the Casper Context Babel plugin in package.json
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
}create or edit your craco.config.js file in project root with this changes
module.exports = {
babel: {
plugins: [['casper-context']]
}
};To avoid undefined variable warnings
globals: {
...require('./casper-eslint.global.js')
}By default, the plugin identifies variables using the _$_ prefix.
// Default usage
let _$_myName = 'Jhone';If you encounter naming collisions or simply prefer a different identifier, you can customize the prefix. Create a .casperctxrc.json file in your project root and specify your preferred prefix
{
"prefix": "CCTX"
}Now, the plugin will look for your custom string instead
// With custom configuration
let CCTXmyName = 'Jhone';To ensure Casper Context transforms your code correctly, please follow these core principles:
Every Casper variable must start with the defined prefix (Default: _$_).
- Correct:
let _$_userName = 'John'; - Incorrect:
let userName = 'John';
Any file that declares, reads, or writes a Casper variable must import React. This is required because the compiled code relies on React.useContext and React.useState.
- Any valid import works:
import React from 'react';import * as React from 'react';
Since Casper variables are converted into Hooks under the hood, they must follow the Rules of Hooks:
- Only declare variables at the top level of your React function component.
- Do not declare them inside loops, conditions, or nested functions.
Currently, Casper variables are treated as globally unique identifiers. You must ensure that every Casper variable name is unique across your entire project, even if they are in different components.
- Example: If you have
_$_userinComponentA, do not use_$_userinComponentB. Use_$_adminUseror_$_customerUserinstead.
Contexts are grouped by the component where the variables are declared.
- All
_$_variables declared in the same component share the same Context. - To create separate Contexts, declare your variables in different components.
Context A (Admin Scope):
function Admin() {
let _$_adminName = 'Jakie';
let _$_adminAge = 34;
// These belong to the 'Admin' Context
}Context B (Customer Scope):
function Customer() {
let _$_customerName = 'Scot';
let _$_customerAge = 25;
// These belong to the 'Customer' Context
}If your variables are not becoming reactive or you see errors in the console, check the following:
- Check the Prefix: Ensure your variable starts exactly with your prefix (Default:
_$_). - Declaration Keyword: Use
letorvarfor variables you intend to update. Usingconstwill prevent you from reassigning the value later. - Babel Cache: Babel often caches transforms. Try restarting your dev server or clearing the cache (e.g.,
rm -rf node_modules/.cache).
Because Casper Context injects variables at compile-time, ESLint might think they are undefined.
- Solution: The plugin automatically generates a
casper-eslint.global.jsfile in your root. Reference this in your.eslintrc.js:const casperGlobals = require('./casper-eslint.global.js'); module.exports = { globals: { ...casperGlobals } };
Babel reads the configuration once when the process starts.
- Solution: If you change your custom prefix in
.casperctxrc.json, you must restart your build tool (Vite, Webpack, or Next.js).
-
Scope: Ensure the variable is declared within a React Component or a file that is part of the Babel transformation path.
-
Hooks Rules: Remember that under the hood, this becomes a React Hook. Do not declare
_$_variables inside nested loops or conditional if statements.
If you are still having trouble, enable debug mode in your .casperctxrc.json
{
"prefix": "_$_",
"debug": true,
"debug_levels": ['reset','info','warn','error', 'debug', 'trace']
}This will generate a .casperctx.debug.log file in your project root, detailing exactly how the plugin is mapping your variables.
- β CRA Support
- β Babel + Webpack Support
- π§ Vite Integration
- π§ Next.js Integration
- π§ TypeScript Improvements
- π§ Developer Tools Integration
Contributions, suggestions, and issues are welcome.
MIT License
