Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

babel-plugin-ng-hot-reload

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

babel-plugin-ng-hot-reload - npm Package Compare versions

Comparing version 2.1.0-alpha003 to 2.1.0-alpha004

3

dist/index.d.ts

@@ -7,4 +7,5 @@ import * as Babel from '@babel/core';

preserveState: boolean;
angularReference: string;
};
export default function (babel: BabelT, { angularGlobal, forceRefresh, preserveState }: PluginOptions): {
export default function (babel: BabelT, { angularGlobal, forceRefresh, preserveState, angularReference, }: PluginOptions): {
name: string;

@@ -11,0 +12,0 @@ post(): void;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function default_1(babel, { angularGlobal = false, forceRefresh = true, preserveState = true }) {
function default_1(babel, { angularGlobal = false, forceRefresh = true, preserveState = true, angularReference = `require('angular'), angular`, }) {
const { types: t, template } = babel;

@@ -8,12 +8,14 @@ let state = {

topLevelExports: new Map(),
angularUseDetected: false,
pathsToRemove: new Set(),
pathsToReplace: new Map(),
};
const registerAngularUse = new Map();
const corePath = 'ng-hot-reload-core';
const requireAngular = '(require("angular"), angular)';
const EXPORTS_PREFIX = '__ngHotReload_';
const INNER_EXPORT_VARIBALE = '__ngHotReload_exports__';
const INNER_EXPORT_VARIABLE = '__ngHotReload_exports__';
const ANGULAR_PACKAGE_NAME = 'angular';
const buildHotReloadTemplate = template(`
/* babel-plugin-ng-hot-reload */
const %%extractedExports%% = (function(__ngHotReloadLoaderAngularGlobal) {
var ${INNER_EXPORT_VARIBALE};
var ${INNER_EXPORT_VARIABLE};
var angular = module.hot ? (function() {

@@ -29,3 +31,3 @@ var loader = require(${JSON.stringify(corePath)});

try {
${INNER_EXPORT_VARIBALE} = (function() {
${INNER_EXPORT_VARIABLE} = (function() {
/* babel-plugin-ng-hot-reload end*/

@@ -47,152 +49,175 @@ %%source%%

}
return ${INNER_EXPORT_VARIBALE};
})(${requireAngular});
return ${INNER_EXPORT_VARIABLE};
})(${angularReference});
/* babel-plugin-ng-hot-reload end */
`);
return {
name: 'ng-hot-reload',
post() {
// Clear the storage after each file
state.topLevelImports.clear();
state.topLevelExports.clear();
state.angularUseDetected = false;
const visitor = {
Program: {
exit(path) {
// Only apply the hot-module-replacement template when usage of angular
// is detected
if (!registerAngularUse.has(path)) {
return;
}
const { node: { body: sourceBody }, } = path;
// Apply all transformations
state.pathsToRemove.forEach((pathToRemove) => pathToRemove.remove());
state.pathsToReplace.forEach((replacer, pathToReplace) => pathToReplace.replaceWith(replacer));
// Adds a return statement to the inner wrapper function which
// contains the exports from the module
// Also adds an destructor to the outside of the wrapper to make the
// exports from inside the wrapper avaiable in global scope
//
// export default Controller;
// export const namedExport
//
// == becomes ==
//
// Appended to wrapped source:
// --
// return {
// __export_default: Controller,
// __export_namedExport: namedExport
// }
//
// Added to outer wrapper:
// --
// const { __export_default, __export_namedExport } = (function() {...})();
//
// Appended to template:
// --
// export {
// __export_default as default,
// __export_namedExport as namedExport
// };
const moduleExports = [];
const extractedExports = [];
const topLevelExports = [];
state.topLevelExports.forEach((value, key) => {
const identifierKey = `${EXPORTS_PREFIX}${key}`;
// Properties of the return statement
moduleExports.push(t.objectProperty(t.identifier(identifierKey), value));
// Properties for the outer const destrcutor
extractedExports.push(t.objectProperty(t.identifier(identifierKey), t.identifier(identifierKey), false, true));
// Restore the topLevelexports
topLevelExports.push(t.exportSpecifier(t.identifier(identifierKey), t.identifier(key)));
});
// Wrap the properties in return statement
const exportsAsReturnStatement = t.returnStatement(t.objectExpression(moduleExports));
// build the template
const hotReloadTemplateAst = buildHotReloadTemplate({
source: sourceBody,
exports: exportsAsReturnStatement,
extractedExports: t.objectPattern(extractedExports),
});
const finalBody = [
...state.topLevelImports.values(),
hotReloadTemplateAst,
topLevelExports.length > 0 ? t.exportNamedDeclaration(null, topLevelExports) : undefined,
].filter(Boolean);
path.node.body = finalBody;
},
},
visitor: {
Program: {
exit(path) {
const { node: { body: sourceBody }, } = path;
// Adds a return statement to the inner wrapper function which
// contains the exports from the module
// Also adds an destructor to the outside of the wrapper to make the
// exports from inside the wrapper avaiable in global scope
//
// export default Controller;
// export const namedExport
//
// == becomes ==
//
// Appended to wrapped source:
// --
// return {
// __export_default: Controller,
// __export_namedExport: namedExport
// }
//
// Added to outer wrapper:
// --
// const { __export_default, __export_namedExport } = (function() {...})();
//
// Appended to template:
// --
// export {
// __export_default as default,
// __export_namedExport as namedExport
// };
const moduleExports = [];
const extractedExports = [];
const topLevelExports = [];
state.topLevelExports.forEach((value, key) => {
const identifierKey = `${EXPORTS_PREFIX}${key}`;
// Properties of the return statement
moduleExports.push(t.objectProperty(t.identifier(identifierKey), value));
// Properties for the outer const destrcutor
extractedExports.push(t.objectProperty(t.identifier(identifierKey), t.identifier(identifierKey), false, true));
// Restore the topLevelexports
topLevelExports.push(t.exportSpecifier(t.identifier(identifierKey), t.identifier(key)));
ImportDeclaration(path) {
const { node } = path;
// Check if the import is angular
if (node.source.value === ANGULAR_PACKAGE_NAME) {
const parentProgram = path.findParent(path => path.isProgram());
registerAngularUse.set(parentProgram, true);
}
// Add import to the list and remove it for now
state.topLevelImports.add(node);
state.pathsToRemove.add(path);
},
ExportNamedDeclaration(path) {
const declaration = path.get('declaration');
if (declaration.node !== null) {
if (declaration.type === 'VariableDeclaration') {
// Export variable declaration
// e.g:
// export const foo = 'bar',
// bar = 'foo';
const { declarations } = declaration.node;
declarations.forEach(declaration => {
const identifier = declaration.id;
state.topLevelExports.set(identifier.name, identifier);
});
// Wrap the properties in return statement
const exportsAsReturnStatement = t.returnStatement(t.objectExpression(moduleExports));
// build the template
const hotReloadTemplateAst = buildHotReloadTemplate({
source: sourceBody,
exports: exportsAsReturnStatement,
extractedExports: t.objectPattern(extractedExports),
});
const finalBody = [
...state.topLevelImports.values(),
hotReloadTemplateAst,
topLevelExports.length > 0
? t.exportNamedDeclaration(null, topLevelExports)
: undefined,
].filter(Boolean);
path.node.body = finalBody;
},
},
ImportDeclaration(path) {
const node = path.node;
// Add it to the list and remove it from the code
state.topLevelImports.add(node);
path.remove();
},
ExportNamedDeclaration(path) {
const declaration = path.get('declaration');
if (declaration.node !== null) {
if (declaration.type === 'VariableDeclaration') {
// Export variable declaration
// e.g:
// export const foo = 'bar',
// bar = 'foo';
const { declarations } = declaration.node;
declarations.forEach(declaration => {
const identifier = declaration.id;
state.topLevelExports.set(identifier.name, identifier);
});
}
else {
// Export right before declaration
// e.g:
// export class Foo {};
const identifier = declaration.get('id').node;
state.topLevelExports.set(identifier.name, identifier);
}
// Replace the export declaration with the actual declaration
path.replaceWith(declaration);
}
else {
// Export specifier
// Export right before declaration
// e.g:
// const foo = 'bar';
// const bar = 'foo';
// export { foo, bar as bar2 };
const { specifiers } = path.node;
if (specifiers && specifiers.length > 0) {
specifiers.forEach(({ local, exported }) => {
state.topLevelExports.set(exported.name, local);
});
}
// Remove the export
path.remove();
// export class Foo {};
const identifier = declaration.get('id').node;
state.topLevelExports.set(identifier.name, identifier);
}
},
ExportDefaultDeclaration(path) {
const declaration = path.get('declaration');
if (declaration.type === 'Identifier' || declaration.type === 'MemberExpression') {
// If export is a simple identifier we can use the node directly
//
// Identifier:
// const foo = 'bar';
// export default foo;
//
// MemberExpression:
// const obj = {
// foo: 'bar'
// };
// export default obj.foo;
state.topLevelExports.set('default', declaration.node);
// Remove the default export
path.remove();
// Replace the export declaration with the actual declaration
state.pathsToReplace.set(path, declaration);
}
else {
// Export specifier
// e.g:
// const foo = 'bar';
// const bar = 'foo';
// export { foo, bar as bar2 };
const { specifiers } = path.node;
if (specifiers && specifiers.length > 0) {
specifiers.forEach(({ local, exported }) => {
state.topLevelExports.set(exported.name, local);
});
}
else {
// If we have a declaration in the default export we have to get the
// identifier through the `id` property
// e.g:
// export default class Foo {}
state.topLevelExports.set('default', declaration.get('id').node);
// Replace the export declaration with the actual declaration
path.replaceWith(declaration);
}
},
// Remove the export
state.pathsToRemove.add(path);
}
},
ExportDefaultDeclaration(path) {
const declaration = path.get('declaration');
if (declaration.type === 'Identifier' || declaration.type === 'MemberExpression') {
// If export is a simple identifier we can use the node directly
//
// Identifier:
// const foo = 'bar';
// export default foo;
//
// MemberExpression:
// const obj = {
// foo: 'bar'
// };
// export default obj.foo;
state.topLevelExports.set('default', declaration.node);
// Remove the default export
state.pathsToRemove.add(path);
}
else {
// If we have a declaration in the default export we have to get the
// identifier through the `id` property
// e.g:
// export default class Foo {}
state.topLevelExports.set('default', declaration.get('id').node);
// Replace the export declaration with the actual declaration
state.pathsToReplace.set(path, declaration);
}
},
};
// When angular is used as global variable check for usage of the identifier
if (angularGlobal) {
visitor['Identifier'] = function (path) {
const { node } = path;
if (node.name === angularGlobal) {
const parentProgram = path.findParent(path => path.isProgram());
registerAngularUse.set(parentProgram, true);
}
};
}
return {
name: 'ng-hot-reload',
post() {
// Clear the storage after each file
state.topLevelImports.clear();
state.topLevelExports.clear();
state.pathsToRemove.clear();
state.pathsToReplace.clear();
},
visitor,
};
}
exports.default = default_1;
{
"name": "babel-plugin-ng-hot-reload",
"version": "2.1.0-alpha003",
"version": "2.1.0-alpha004",
"main": "dist/index.js",

@@ -5,0 +5,0 @@ "author": {

@@ -12,3 +12,3 @@ # 🔥 babel-plugin-ng-hot-reload

> - [Webpack / TypeScript demo on CodeSandbox](https://codesandbox.io/s/github/ofhouse/babel-plugin-ng-hot-reload/tree/master/examples/typescript-webpack)
> - [Parcel / TypeScript demo on CodeSandbox](https://codesandbox.io/s/github/ofhouse/babel-plugin-ng-hot-reload/tree/master/examples/typescript-parcel) (There are some issues, see: [FAQ](#known-issues-with-parcel))
> - [Parcel / TypeScript demo on CodeSandbox](https://codesandbox.io/s/github/ofhouse/babel-plugin-ng-hot-reload/tree/master/examples/typescript-parcel) (There is an issue with HTML import, see: [FAQ](#known-issues-with-parcel))

@@ -37,2 +37,3 @@ ```sh

preserveState: true,
angularReference: "require('angular'), angular",
},

@@ -46,7 +47,8 @@ ],

| Option | Default | Description |
| --------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `angularGlobal` | `false` (false or string) | Define whether angular is provided as global variable. Set to `'angular'` when `angular` is your global variable. |
| `forceRefresh` | `true` (boolean) | Whether to reload window automatically when a change in source files can't be hot-reloaded. Note that Webpack DevServer also has its own option hotOnly, which should also be configured correctly to get the behaviour you want when hot reloading fails.<br />([ng-hot-reload option](https://github.com/noppa/ng-hot-reload#client-options)) |
| `preserveState` | `true` (boolean) | If true, the library attempts to preserve some state in scope and controller instances when they are reloaded. Preserving state is an experimental feature and quite "hackish" so it may cause problems in some cases. Setting this to `false` might help if you run into weird errors.<br />([ng-hot-reload option](https://github.com/noppa/ng-hot-reload#client-options)) |
| Option | Default | Description |
| ------------------ | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `angularGlobal` | `false` (false or string) | Define whether angular is provided as global variable. Set to `'angular'` when `angular` is your global variable. |
| `forceRefresh` | `true` (boolean) | Whether to reload window automatically when a change in source files can't be hot-reloaded. Note that Webpack DevServer also has its own option hotOnly, which should also be configured correctly to get the behaviour you want when hot reloading fails.<br />([ng-hot-reload option](https://github.com/noppa/ng-hot-reload#client-options)) |
| `preserveState` | `true` (boolean) | If true, the library attempts to preserve some state in scope and controller instances when they are reloaded. Preserving state is an experimental feature and quite "hackish" so it may cause problems in some cases. Setting this to `false` might help if you run into weird errors.<br />([ng-hot-reload option](https://github.com/noppa/ng-hot-reload#client-options)) |
| `angularReference` | `"require('angular'), angular"` (string) | JavaScript expression that will be evaluated to get a reference to angular.<br />([ng-hot-reload option](https://github.com/noppa/ng-hot-reload#client-options)) |

@@ -76,2 +78,37 @@ ## FAQ

### Use AngularJS as global variable
Per default the plugin looks for imports of `'angular'`-package and only adds the hot-module-reload code to this modules.
However in some environments angular is used as a global variable without beeing imported, so the plugin has a `angularGlobal` setting which supports the use of angular as a global variable:
```js
// Default mode: Add hot-module-reload only to files which import 'angular'
// app.module.js
import * as angular from 'angular'; // or
import angular from 'angular'; // or
import 'angular';
angular.module('hot-reload-demo', []);
////////////////////////////////////////////////////////////////////////////////
// Setting angularGlobal option: Use `angular` as global variable
// .babelrc.json
module.exports = {
plugins: [
[
'babel-plugin-ng-hot-reload',
{
angularGlobal: 'angular', // Name of the global angular variable
},
],
],
};
// app.module.js
angular.module('hot-reload-demo', []);
```
For an example check out the [Webpack / Javascript example](./examples/javascript-webpack/).
### Use together with `ngAnnotate`

@@ -94,6 +131,5 @@

Unfortunatly there are currently some issues related to parcel:
Unfortunatly there are currently an issue related to parcel:
- No hot-module-replacement for HTML templates ([parcel#943](https://github.com/parcel-bundler/parcel/issues/943))
- Importing CSS from TypeScript file does not work (See [`fade.component.ts`](./examples/typescript-parcel/src/fade/fade.component.ts))

@@ -100,0 +136,0 @@ ## Author

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