New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

solid-refresh

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

solid-refresh - npm Package Compare versions

Comparing version 0.2.2 to 0.3.0

345

babel.js

@@ -1,114 +0,237 @@

module.exports = ({ types: t }) => {
return {
name: "Solid Refresh",
visitor: {
Program(path, { opts }) {
const comments = path.hub.file.ast.comments;
for (let i = 0; i < comments.length; i++) {
const comment = comments[i];
const index = comment.value.indexOf("@refresh");
if (index > -1) {
if (comment.value.slice(index).includes("skip")) {
path.hub.file.metadata.processedHot = true;
return;
'use strict';
var t = require('@babel/types');
var generator = require('@babel/generator');
var helperModuleImports = require('@babel/helper-module-imports');
var crypto = require('crypto');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () {
return e[k];
}
});
}
if (comment.value.slice(index).includes("reload")) {
if (opts.bundler === "vite") opts.bundler = "esm";
path.hub.file.metadata.processedHot = true;
const pathToHot =
opts.bundler !== "esm"
? t.memberExpression(t.identifier("module"), t.identifier("hot"))
: t.memberExpression(
t.memberExpression(t.identifier("import"), t.identifier("meta")),
t.identifier("hot")
);
path.pushContainer(
"body",
t.ifStatement(
pathToHot,
t.expressionStatement(
t.callExpression(t.memberExpression(pathToHot, t.identifier("decline")), [])
)
)
);
return;
});
}
n['default'] = e;
return Object.freeze(n);
}
var t__namespace = /*#__PURE__*/_interopNamespace(t);
var generator__default = /*#__PURE__*/_interopDefaultLegacy(generator);
var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
function isComponentishName(name) {
return typeof name === 'string' && name[0] >= 'A' && name[0] <= 'Z';
}
function getSolidRefreshIdentifier(hooks, path, name) {
const current = hooks.get(name);
if (current) {
return current;
}
const newID = helperModuleImports.addNamed(path, name, 'solid-refresh');
hooks.set(name, newID);
return newID;
}
function getHotIdentifier(bundler) {
if (bundler === 'esm') {
return t__namespace.memberExpression(t__namespace.memberExpression(t__namespace.identifier('import'), t__namespace.identifier('meta')), t__namespace.identifier('hot'));
}
return t__namespace.memberExpression(t__namespace.identifier("module"), t__namespace.identifier("hot"));
}
function getStatementPath(path) {
if (t__namespace.isStatement(path.node)) {
return path;
}
if (path.parentPath) {
return getStatementPath(path.parentPath);
}
return null;
}
function createHotMap(hooks, path, name) {
const current = hooks.get(name);
if (current) {
return current;
}
const newID = t__namespace.identifier(name);
path.insertBefore(t__namespace.exportNamedDeclaration(t__namespace.variableDeclaration('const', [t__namespace.variableDeclarator(newID, t__namespace.objectExpression([]))])));
hooks.set(name, newID);
return newID;
}
function createSignature(node) {
const code = generator__default['default'](node);
const result = crypto__default['default'].createHash('sha256').update(code.code).digest('base64');
return result;
}
function createStandardHot(path, hooks, opts, HotComponent, rename) {
const HotImport = getSolidRefreshIdentifier(hooks, path, opts.bundler || 'standard');
const pathToHot = getHotIdentifier(opts.bundler);
const statementPath = getStatementPath(path);
if (statementPath) {
statementPath.insertBefore(rename);
}
return t__namespace.callExpression(HotImport, [
HotComponent,
t__namespace.stringLiteral(HotComponent.name),
t__namespace.stringLiteral(createSignature(rename)),
pathToHot,
]);
}
function createESMHot(path, hooks, opts, HotComponent, rename) {
const HotImport = getSolidRefreshIdentifier(hooks, path, opts.bundler || 'standard');
const pathToHot = getHotIdentifier(opts.bundler);
const handlerId = path.scope.generateUidIdentifier("handler");
const componentId = path.scope.generateUidIdentifier("Component");
const statementPath = getStatementPath(path);
if (statementPath) {
const registrationMap = createHotMap(hooks, statementPath, '$$registrations');
statementPath.insertBefore(rename);
statementPath.insertBefore(t__namespace.expressionStatement(t__namespace.assignmentExpression('=', t__namespace.memberExpression(registrationMap, HotComponent), t__namespace.objectExpression([
t__namespace.objectProperty(t__namespace.identifier('component'), HotComponent),
t__namespace.objectProperty(t__namespace.identifier('signature'), t__namespace.stringLiteral(createSignature(rename))),
]))));
statementPath.insertBefore(t__namespace.variableDeclaration("const", [
t__namespace.variableDeclarator(t__namespace.objectPattern([
t__namespace.objectProperty(t__namespace.identifier('handler'), handlerId, false, true),
t__namespace.objectProperty(t__namespace.identifier('Component'), componentId, false, true)
]), t__namespace.callExpression(HotImport, [
HotComponent,
t__namespace.stringLiteral(HotComponent.name),
t__namespace.memberExpression(t__namespace.memberExpression(registrationMap, HotComponent), t__namespace.identifier('signature')),
t__namespace.unaryExpression("!", t__namespace.unaryExpression("!", pathToHot))
]))
]));
statementPath.insertBefore(t__namespace.ifStatement(pathToHot, t__namespace.expressionStatement(t__namespace.callExpression(t__namespace.memberExpression(pathToHot, t__namespace.identifier("accept")), [handlerId]))));
}
return componentId;
}
function createHot(path, hooks, opts, name, expression) {
if (opts.bundler === "vite")
opts.bundler = "esm";
const HotComponent = name
? path.scope.generateUidIdentifier(`Hot$$${name.name}`)
: path.scope.generateUidIdentifier('HotComponent');
const rename = t__namespace.variableDeclaration("const", [
t__namespace.variableDeclarator(HotComponent, expression),
]);
if (opts.bundler === "esm") {
return createESMHot(path, hooks, opts, HotComponent, rename);
}
return createStandardHot(path, hooks, opts, HotComponent, rename);
}
function solidRefreshPlugin() {
return {
name: 'Solid Refresh',
pre() {
this.hooks = new Map();
this.processed = {
value: false,
};
},
visitor: {
Program(path, { opts, processed }) {
const comments = path.hub.file.ast.comments;
for (let i = 0; i < comments.length; i++) {
const comment = comments[i].value;
if (/^\s*@refresh skip\s*$/.test(comment)) {
processed.value = true;
return;
}
if (/^\s*@refresh reload\s*$/.test(comment)) {
if (opts.bundler === "vite")
opts.bundler = "esm";
processed.value = true;
const pathToHot = getHotIdentifier(opts.bundler);
path.pushContainer("body", t__namespace.ifStatement(pathToHot, t__namespace.expressionStatement(t__namespace.callExpression(t__namespace.memberExpression(pathToHot, t__namespace.identifier("decline")), []))));
return;
}
}
},
ExportNamedDeclaration(path, { opts, hooks, processed }) {
if (processed.value) {
return;
}
const decl = path.node.declaration;
// Check if declaration is FunctionDeclaration
if (t__namespace.isFunctionDeclaration(decl) && !(decl.generator || decl.async)) {
// Check if the declaration has an identifier, and then check
// if the name is component-ish
if (decl.id && isComponentishName(decl.id.name)) {
path.node.declaration = t__namespace.variableDeclaration('const', [
t__namespace.variableDeclarator(decl.id, createHot(path, hooks, opts, decl.id, t__namespace.functionExpression(decl.id, decl.params, decl.body)))
]);
}
}
},
VariableDeclarator(path, { opts, hooks, processed }) {
var _a, _b;
if (processed.value) {
return;
}
const grandParentNode = (_b = (_a = path.parentPath) === null || _a === void 0 ? void 0 : _a.parentPath) === null || _b === void 0 ? void 0 : _b.node;
// Check if the parent of the VariableDeclaration
// is either a Program or an ExportNamedDeclaration
if (t__namespace.isProgram(grandParentNode)
|| t__namespace.isExportNamedDeclaration(grandParentNode)) {
const identifier = path.node.id;
const init = path.node.init;
if (t__namespace.isIdentifier(identifier)
&& isComponentishName(identifier.name)
&& (
// Check for valid FunctionExpression
(t__namespace.isFunctionExpression(init) && !(init.async || init.generator))
// Check for valid ArrowFunctionExpression
|| (t__namespace.isArrowFunctionExpression(init) && !(init.async || init.generator)))) {
path.node.init = createHot(path, hooks, opts, identifier, init);
}
}
},
FunctionDeclaration(path, { opts, hooks, processed }) {
if (processed.value) {
return;
}
if (!(t__namespace.isProgram(path.parentPath.node)
|| t__namespace.isExportDefaultDeclaration(path.parentPath.node))) {
return;
}
const decl = path.node;
// Check if declaration is FunctionDeclaration
if (!(decl.generator || decl.async)) {
// Check if the declaration has an identifier, and then check
// if the name is component-ish
if (decl.id && isComponentishName(decl.id.name)) {
const replacement = createHot(path, hooks, opts, decl.id, t__namespace.functionExpression(decl.id, decl.params, decl.body));
if (t__namespace.isExportDefaultDeclaration(path.parentPath.node)) {
path.replaceWith(replacement);
}
else {
path.replaceWith(t__namespace.variableDeclaration('var', [
t__namespace.variableDeclarator(decl.id, replacement),
]));
}
}
else if (!decl.id
&& decl.params.length === 1
&& t__namespace.isIdentifier(decl.params[0])
&& decl.params[0].name === 'props'
&& t__namespace.isExportDefaultDeclaration(path.parentPath.node)) {
const replacement = createHot(path, hooks, opts, undefined, t__namespace.functionExpression(null, decl.params, decl.body));
path.replaceWith(replacement);
}
}
}
}
}
},
ExportDefaultDeclaration(path, { opts }) {
if (path.hub.file.metadata.processedHot) return;
if (
path.hub.file.opts.parserOpts.sourceFileName &&
!path.hub.file.opts.parserOpts.sourceFileName.endsWith(".jsx") &&
!path.hub.file.opts.parserOpts.sourceFileName.endsWith(".tsx")
)
return;
if (opts.bundler === "vite") opts.bundler = "esm";
path.hub.file.metadata.processedHot = true;
const decl = path.node.declaration;
const HotComponent = t.identifier("$HotComponent");
const HotImport = t.identifier("_$hot");
const pathToHot =
opts.bundler !== "esm"
? t.memberExpression(t.identifier("module"), t.identifier("hot"))
: t.memberExpression(
t.memberExpression(t.identifier("import"), t.identifier("meta")),
t.identifier("hot")
);
const rename = t.variableDeclaration("const", [
t.variableDeclarator(
HotComponent,
t.isFunctionDeclaration(decl)
? t.functionExpression(decl.id, decl.params, decl.body)
: decl
)
]);
let replacement;
if (opts.bundler === "esm") {
const handlerId = t.identifier("_$handler");
const componentId = t.identifier("_$Component");
replacement = [
t.importDeclaration(
[t.importSpecifier(HotImport, t.identifier(opts.bundler || "standard"))],
t.stringLiteral("solid-refresh")
),
t.exportNamedDeclaration(rename),
t.variableDeclaration("const", [
t.variableDeclarator(
t.objectPattern([
t.objectProperty(handlerId, handlerId, false, true),
t.objectProperty(componentId, componentId, false, true)
]),
t.callExpression(HotImport, [
HotComponent,
t.unaryExpression("!", t.unaryExpression("!", pathToHot))
])
)
]),
t.ifStatement(
pathToHot,
t.expressionStatement(
t.callExpression(t.memberExpression(pathToHot, t.identifier("accept")), [handlerId])
)
),
t.exportDefaultDeclaration(componentId)
];
} else {
replacement = [
t.importDeclaration(
[t.importSpecifier(HotImport, t.identifier(opts.bundler || "standard"))],
t.stringLiteral("solid-refresh")
),
rename,
t.exportDefaultDeclaration(t.callExpression(HotImport, [HotComponent, pathToHot]))
];
}
},
};
}
path
.replaceWithMultiple(replacement)
.forEach(declaration => path.scope.registerDeclaration(declaration));
}
}
};
};
module.exports = solidRefreshPlugin;

@@ -7,38 +7,55 @@ 'use strict';

function hot$1(Comp, hot) {
if (hot) {
const [comp, setComp] = solidJs.createSignal(Comp);
const prev = hot.data;
if (prev && prev.setComp) {
prev.setComp(() => Comp);
function hot$1(Comp, id, initialSignature, hot) {
if (hot) {
const [comp, setComp] = solidJs.createSignal(Comp);
const [sign, setSign] = solidJs.createSignal(initialSignature);
const prev = hot.data;
if (prev && prev[id] && prev[id].sign() !== initialSignature) {
prev[id].setSign(() => initialSignature);
prev[id].setComp(() => Comp);
}
hot.dispose(data => {
data[id] = prev ? prev[id] : {
setComp,
sign,
setSign,
};
});
hot.accept();
let c;
return new Proxy((props) => solidJs.createMemo(() => (c = comp()) && solidJs.untrack(() => c(props))), {
get(_, property) {
return comp()[property];
}
});
}
hot.dispose(data => (data.setComp = prev ? prev.setComp : setComp));
hot.accept();
let c;
return new Proxy(props => solidJs.createMemo(() => (c = comp()) && solidJs.untrack(() => c(props))), {
get(_, property) {
return comp()[property];
}
});
}
return Comp;
return Comp;
}
function hot(Comp, isHot) {
let _$Component = Comp;
function _$handler(newModule) {
newModule.$HotComponent.setComp = Comp.setComp;
Comp.setComp(() => newModule.$HotComponent);
}
if (isHot) {
const [comp, setComp] = solidJs.createSignal(Comp);
Comp.setComp = setComp;
let c;
_$Component = new Proxy(props => solidJs.createMemo(() => (c = comp()) && solidJs.untrack(() => c(props))), {
get(_, property) {
return comp()[property];
}
});
}
return { _$Component, _$handler };
function hot(Comp, id, initialSignature, isHot) {
let Component = Comp;
function handler(newModule) {
const registration = newModule.$$registrations[id];
registration.component.setComp = Comp.setComp;
registration.component.setSign = Comp.setSign;
registration.component.sign = Comp.sign;
if (registration.signature !== Comp.sign()) {
Comp.setSign(() => registration.signature);
Comp.setComp(() => registration.component);
}
}
if (isHot) {
const [comp, setComp] = solidJs.createSignal(Comp);
const [signature, setSignature] = solidJs.createSignal(initialSignature);
Comp.setComp = setComp;
Comp.setSign = setSignature;
Comp.sign = signature;
let c;
Component = new Proxy((props) => solidJs.createMemo(() => (c = comp()) && solidJs.untrack(() => c(props))), {
get(_, property) {
return comp()[property];
}
});
}
return { Component, handler };
}

@@ -45,0 +62,0 @@

@@ -6,3 +6,3 @@ {

"license": "MIT",
"version": "0.2.2",
"version": "0.3.0",
"homepage": "https://github.com/solidjs/solid-refresh#readme",

@@ -19,2 +19,8 @@ "repository": {

],
"publishConfig": {
"access": "public"
},
"contributors": [
"Alexis Munsayac"
],
"sideEffects": false,

@@ -27,8 +33,16 @@ "scripts": {

"@rollup/plugin-node-resolve": "13.0.0",
"@rollup/plugin-typescript": "^8.3.0",
"rollup": "^2.52.1",
"solid-js": "^1.0.0"
"solid-js": "^1.0.0",
"@types/babel__core": "^7.1.16",
"@babel/core": "^7.16.0"
},
"peerDependencies": {
"solid-js": "^1.0.0"
},
"dependencies": {
"@babel/types": "^7.16.0",
"@babel/helper-module-imports": "^7.16.0",
"@babel/generator": "^7.16.0"
}
}

@@ -11,16 +11,40 @@ # Solid Refresh

* Snowpack (with option `bundler: "esm"`, need to confirm)
## How it works
The babel plugin will transform files with `.jsx` or `.tsx` extensions with default exports (assuming they are component files) to wrap the default export with `createMemo` call so component can be swapped at will.
The babel plugin will transform components with matching Pascal-cased names (indicating that they are components). This detection is supported in variable declarations, function declarations and named exports:
Today we don't preserve state below the change.
```jsx
// This works
function Foo() {
return <h1>Hello Foo</h1>;
}
// This also works
const Bar = () => <h1>Hello Bar</h1>;
```
Anonymous functions with `props` as the only parameter are also supported.
```js
// This also works
export default function (props) {
return <h1>Hello Anonymous!</h1>;
}
```
The components are wrapped and memoized. When the module receives an update, it tries to detect if the component's content has changed between updates, prompting a remount for the changed component (which allows the ancestor components to retain their lifecycle.).
## Pragma
On a per file basis, use comments at top of file to opt out(change moves up to parent):
```js
/* @refresh skip */
```
Or force reload:
```js
/* @refresh reload */
```

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc