babel-plugin-ng-hot-reload
Advanced tools
Comparing version 2.1.0-alpha002 to 2.1.0-alpha003
import * as Babel from '@babel/core'; | ||
declare type BabelT = typeof Babel; | ||
declare type PluginOptions = {}; | ||
export default function (babel: BabelT, options?: PluginOptions): { | ||
declare type PluginOptions = { | ||
angularGlobal: false | string; | ||
forceRefresh: boolean; | ||
preserveState: boolean; | ||
}; | ||
export default function (babel: BabelT, { angularGlobal, forceRefresh, preserveState }: PluginOptions): { | ||
name: string; | ||
@@ -6,0 +10,0 @@ post(): void; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function default_1(babel, options = {}) { | ||
const { types: t } = babel; | ||
const state = { | ||
function default_1(babel, { angularGlobal = false, forceRefresh = true, preserveState = true }) { | ||
const { types: t, template } = babel; | ||
let state = { | ||
topLevelImports: new Set(), | ||
topLevelExports: new Map(), | ||
angularUseDetected: false, | ||
}; | ||
const corePath = JSON.stringify(require.resolve('ng-hot-reload-core')); | ||
// const corePath = "testPath"; | ||
const corePath = 'ng-hot-reload-core'; | ||
const requireAngular = '(require("angular"), angular)'; | ||
const forceRefresh = false; | ||
const preserveState = false; | ||
const SOURCE_PLACEHOLDER = '__SOURCE_PLACEHOLDER__'; | ||
const EXPORTS_PLACEHOLDER = '__EXPORTS_PLACEHOLDER__'; | ||
const EXPORTS_PREFIX = '$$__export__'; | ||
const hotReloadTemplate = ` | ||
/* ng-hot-reload-loader */ | ||
const { } = (function(__ngHotReloadLoaderAngularGlobal) { | ||
var $$__exports__; | ||
const EXPORTS_PREFIX = '__ngHotReload_'; | ||
const INNER_EXPORT_VARIBALE = '__ngHotReload_exports__'; | ||
const buildHotReloadTemplate = template(` | ||
/* babel-plugin-ng-hot-reload */ | ||
const %%extractedExports%% = (function(__ngHotReloadLoaderAngularGlobal) { | ||
var ${INNER_EXPORT_VARIBALE}; | ||
var angular = module.hot ? (function() { | ||
var loader = require(${corePath}); | ||
var loader = require(${JSON.stringify(corePath)}); | ||
return loader.decorateAngular({ | ||
angular: __ngHotReloadLoaderAngularGlobal, | ||
forceRefresh: Boolean(${forceRefresh}), | ||
preserveState: Boolean(${preserveState}) | ||
forceRefresh: ${JSON.stringify(forceRefresh)}, | ||
preserveState: ${JSON.stringify(preserveState)} | ||
}); | ||
@@ -31,9 +28,7 @@ })() : __ngHotReloadLoaderAngularGlobal; | ||
try { | ||
$$__exports__ = (function() { | ||
/* ng-hot-reload-loader end*/ | ||
'${SOURCE_PLACEHOLDER}'; | ||
'${EXPORTS_PLACEHOLDER}'; | ||
/* ng-hot-reload-loader */ | ||
${INNER_EXPORT_VARIBALE} = (function() { | ||
/* babel-plugin-ng-hot-reload end*/ | ||
%%source%% | ||
/* babel-plugin-ng-hot-reload */ | ||
%%exports%% | ||
})(); | ||
@@ -51,6 +46,6 @@ } finally { | ||
} | ||
return $$__exports__; | ||
return ${INNER_EXPORT_VARIBALE}; | ||
})(${requireAngular}); | ||
/* ng-hot-reload-loader end */ | ||
`; | ||
/* babel-plugin-ng-hot-reload end */ | ||
`); | ||
return { | ||
@@ -62,2 +57,3 @@ name: 'ng-hot-reload', | ||
state.topLevelExports.clear(); | ||
state.angularUseDetected = false; | ||
}, | ||
@@ -68,44 +64,56 @@ visitor: { | ||
const { node: { body: sourceBody }, } = path; | ||
const parsedTemplate = babel.parse(hotReloadTemplate); | ||
babel.traverse(parsedTemplate, { | ||
Directive(path) { | ||
const { node } = path; | ||
// Add the source code to the SOURCE_PLACEHOLDER | ||
if (node.value && | ||
node.value.type === 'DirectiveLiteral' && | ||
node.value.value === SOURCE_PLACEHOLDER) { | ||
path.replaceWithMultiple(sourceBody); | ||
} | ||
if (node.value && | ||
node.value.type === 'DirectiveLiteral' && | ||
node.value.value === EXPORTS_PLACEHOLDER) { | ||
const __exports = []; | ||
state.topLevelExports.forEach((value, key) => { | ||
__exports.push(t.objectProperty(t.identifier(`${EXPORTS_PREFIX}${key}`), value)); | ||
}); | ||
path.replaceWith(t.returnStatement(t.objectExpression(__exports))); | ||
} | ||
}, | ||
VariableDeclaration(path) { | ||
if (path.parent.type === 'Program') { | ||
const __exports = []; | ||
state.topLevelExports.forEach((_, key) => { | ||
__exports.push(t.objectProperty(t.identifier(`${EXPORTS_PREFIX}${key}`), t.identifier(`${EXPORTS_PREFIX}${key}`), false, true)); | ||
}); | ||
path | ||
.get('declarations')[0] | ||
.get('id') | ||
.replaceWith(t.objectPattern(__exports)); | ||
} | ||
}, | ||
}); | ||
const __exports = []; | ||
// 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) => { | ||
__exports.push(t.exportSpecifier(t.identifier(`${EXPORTS_PREFIX}${key}`), t.identifier(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))); | ||
}); | ||
const finalExports = t.exportNamedDeclaration(null, __exports); | ||
const finalBody = [...state.topLevelImports.values(), parsedTemplate]; | ||
if (__exports.length) { | ||
finalBody.push(finalExports); | ||
} | ||
// 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; | ||
@@ -112,0 +120,0 @@ }, |
{ | ||
"name": "babel-plugin-ng-hot-reload", | ||
"version": "2.1.0-alpha002", | ||
"version": "2.1.0-alpha003", | ||
"main": "dist/index.js", | ||
@@ -5,0 +5,0 @@ "author": { |
# 🔥 babel-plugin-ng-hot-reload | ||
A babel plugin which enables hot module replacement in angular.js applications.<br /> | ||
A babel plugin which enables hot module replacement in AngularJS applications.<br /> | ||
The plugin is based on the [ng-hot-reload](https://github.com/noppa/ng-hot-reload) webpack loader but is rewritten as babel plugin so that it is compatible with es-module syntax and every bundler which supports the hot-replacement API (e.g. [webpack](https://webpack.js.org/) or [parcel](https://parceljs.org/)). | ||
@@ -12,2 +12,3 @@ | ||
> - [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)) | ||
@@ -34,4 +35,4 @@ ```sh | ||
angularGlobal: false, | ||
forceRefresh: false, | ||
preserveState: false, | ||
forceRefresh: true, | ||
preserveState: true, | ||
}, | ||
@@ -45,8 +46,14 @@ ], | ||
| 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)) | | ||
## FAQ | ||
### Use it together with `@babel/preset-env` | ||
### Use together with `@babel/preset-env` | ||
This plugin should be work nicly together with the `@babel/preset-env` plugin. | ||
In opposite to the original webpack-loader it's **not** required to transpile your code to commonjs modules: | ||
This plugin should work nicely together with the [`@babel/preset-env`](https://babeljs.io/docs/en/babel-preset-env) plugin. | ||
In opposite to the original ng-hot-reload webpack-loader it's **not** required to transpile your code to commonjs modules: | ||
@@ -59,3 +66,3 @@ ```js | ||
{ | ||
modules: false, // Don't transpile the modules | ||
modules: false, // Don't transpile the modules (default) | ||
}, | ||
@@ -70,3 +77,3 @@ ], | ||
### Use together with ngAnnotate | ||
### Use together with `ngAnnotate` | ||
@@ -83,2 +90,12 @@ When you are using this plugin together with [`babel-plugin-angularjs-annotate`](https://github.com/schmod/babel-plugin-angularjs-annotate) make sure that the ngAnnotate plugin is added before this plugin in your `.babelrc.js`: | ||
### Known issues with parcel | ||
Since this plugin only requires babel, you can use every build tool which supports hot-module-replacement.<br /> | ||
You can check out the [Parcel / TypeScript example](./examples/typescript-parcel/) to see how it works with other bundlers than webpack. | ||
Unfortunatly there are currently some issues 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)) | ||
## Author | ||
@@ -85,0 +102,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
16848
214
107