Socket
Socket
Sign inDemoInstall

@pmmmwh/react-refresh-webpack-plugin

Package Overview
Dependencies
Maintainers
1
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pmmmwh/react-refresh-webpack-plugin - npm Package Compare versions

Comparing version 0.5.0-beta.9 to 0.5.0-rc.0

lib/utils/makeRefreshRuntimeModule.js

31

lib/globals.js

@@ -1,13 +0,22 @@

const { version } = require('webpack');
/**
* Gets current bundle's global scope identifier for React Refresh.
* @param {Record<string, string>} runtimeGlobals The Webpack runtime globals.
* @returns {string} The React Refresh global scope within the Webpack bundle.
*/
module.exports.getRefreshGlobalScope = (runtimeGlobals) => {
return `${runtimeGlobals.require || '__webpack_require__'}.$Refresh$`;
};
// Parse the major version of Webpack: x.y.z => x
const webpackVersion = parseInt(version || '', 10);
/**
* Gets current Webpack version according to features on the compiler instance.
* @param {import('webpack').Compiler} compiler The current Webpack compiler instance.
* @returns {number} The current Webpack version.
*/
module.exports.getWebpackVersion = (compiler) => {
if (!compiler.hooks) {
throw new Error(`[ReactRefreshPlugin] Webpack version is not supported!`);
}
let webpackGlobals = {};
if (webpackVersion === 5) {
webpackGlobals = require('webpack/lib/RuntimeGlobals');
}
module.exports.webpackVersion = webpackVersion;
module.exports.webpackRequire = webpackGlobals.require || '__webpack_require__';
module.exports.refreshGlobal = `${module.exports.webpackRequire}.$Refresh$`;
// Webpack v5+ implements compiler caching
return 'cache' in compiler ? 5 : 4;
};
const { validate: validateOptions } = require('schema-utils');
const { getRefreshGlobalScope, getWebpackVersion } = require('./globals');
const {
DefinePlugin,
EntryPlugin,
ModuleFilenameHelpers,
ProvidePlugin,
Template,
} = require('webpack');
const ConstDependency = require('webpack/lib/dependencies/ConstDependency');
const { refreshGlobal, webpackRequire, webpackVersion } = require('./globals');
const {
getAdditionalEntries,
getIntegrationEntry,
getParserHelpers,
getRefreshGlobal,

@@ -19,2 +10,3 @@ getSocketIntegration,

injectRefreshLoader,
makeRefreshRuntimeModule,
normalizeOptions,

@@ -24,16 +16,2 @@ } = require('./utils');

// Mapping of react-refresh globals to Webpack runtime globals
const REPLACEMENTS = {
$RefreshReg$: {
expr: `${refreshGlobal}.register`,
req: [webpackRequire, `${refreshGlobal}.register`],
type: 'function',
},
$RefreshSig$: {
expr: `${refreshGlobal}.signature`,
req: [webpackRequire, `${refreshGlobal}.signature`],
type: 'function',
},
};
class ReactRefreshPlugin {

@@ -62,8 +40,2 @@ /**

apply(compiler) {
// Throw if we encounter an unsupported Webpack version,
// since things will most likely not work.
if (webpackVersion !== 4 && webpackVersion !== 5) {
throw new Error(`[ReactRefreshPlugin] Webpack v${webpackVersion} is not supported!`);
}
// Skip processing in non-development mode, but allow manual force-enabling

@@ -82,9 +54,23 @@ if (

const webpackVersion = getWebpackVersion(compiler);
const logger = compiler.getInfrastructureLogger(this.constructor.name);
let loggedHotWarning = false;
// Get Webpack imports from compiler instance (if available) -
// this allow mono-repos to use different versions of Webpack without conflicts.
const webpack = compiler.webpack || require('webpack');
const {
DefinePlugin,
EntryDependency,
EntryPlugin,
ModuleFilenameHelpers,
NormalModule,
ProvidePlugin,
RuntimeGlobals,
Template,
} = webpack;
// Inject react-refresh context to all Webpack entry points.
// This should create `EntryDependency` objects when available,
// and fallback to patching the `entry` object for legacy workflows.
const additional = getAdditionalEntries({
const addEntries = getAdditionalEntries({
devServer: compiler.options.devServer,

@@ -96,3 +82,3 @@ options: this.options,

// so we can utilise EntryPlugin for simpler logic.
additional.prependEntries.forEach((entry) => {
addEntries.prependEntries.forEach((entry) => {
new EntryPlugin(compiler.context, entry, { name: undefined }).apply(compiler);

@@ -122,3 +108,3 @@ });

// This ensures we can traverse all entry points and inject stuff with the correct order.
additional.overlayEntries.forEach((entry, idx, arr) => {
addEntries.overlayEntries.forEach((entry, idx, arr) => {
compiler.hooks.finishMake.tapPromise(

@@ -163,8 +149,16 @@ { name: this.constructor.name, stage: Number.MIN_SAFE_INTEGER + (arr.length - idx - 1) },

} else {
compiler.options.entry = injectRefreshEntry(compiler.options.entry, additional);
compiler.options.entry = injectRefreshEntry(compiler.options.entry, addEntries);
}
// Inject necessary modules to bundle's global scope
// Inject necessary modules and variables to bundle's global scope
const refreshGlobal = getRefreshGlobalScope(RuntimeGlobals || {});
/** @type {Record<string, string | boolean>}*/
const definedModules = {
// Mapping of react-refresh globals to Webpack runtime globals
$RefreshReg$: `${refreshGlobal}.register`,
$RefreshSig$: `${refreshGlobal}.signature`,
'typeof $RefreshReg$': 'function',
'typeof $RefreshSig$': 'function',
// Library mode
__react_refresh_library__: JSON.stringify(

@@ -207,3 +201,3 @@ Template.toIdentifier(

const match = ModuleFilenameHelpers.matchObject.bind(undefined, this.options);
const { evaluateToString, toConstantDependency } = getParserHelpers();
let loggedHotWarning = false;
compiler.hooks.compilation.tap(

@@ -217,5 +211,2 @@ this.constructor.name,

// Set template for ConstDependency which is used by parser hooks
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
// Tap into version-specific compilation hooks

@@ -290,3 +281,3 @@ switch (webpackVersion) {

(source) => {
return Template.asString([source, '', getRefreshGlobal()]);
return Template.asString([source, '', getRefreshGlobal(Template)]);
}

@@ -327,10 +318,6 @@ );

case 5: {
const EntryDependency = require('webpack/lib/dependencies/EntryDependency');
const NormalModule = require('webpack/lib/NormalModule');
const RuntimeGlobals = require('webpack/lib/RuntimeGlobals');
const ReactRefreshRuntimeModule = require('./RefreshRuntimeModule');
// Set factory for EntryDependency which is used to initialise the module
compilation.dependencyFactories.set(EntryDependency, normalModuleFactory);
const ReactRefreshRuntimeModule = makeRefreshRuntimeModule(webpack);
compilation.hooks.additionalTreeRuntimeRequirements.tap(

@@ -385,31 +372,2 @@ this.constructor.name,

}
/**
* Transform global calls into Webpack runtime calls.
* @param {*} parser
* @returns {void}
*/
const parserHandler = (parser) => {
Object.entries(REPLACEMENTS).forEach(([key, info]) => {
parser.hooks.expression
.for(key)
.tap(this.constructor.name, toConstantDependency(parser, info.expr, info.req));
if (info.type) {
parser.hooks.evaluateTypeof
.for(key)
.tap(this.constructor.name, evaluateToString(info.type));
}
});
};
normalModuleFactory.hooks.parser
.for('javascript/auto')
.tap(this.constructor.name, parserHandler);
normalModuleFactory.hooks.parser
.for('javascript/dynamic')
.tap(this.constructor.name, parserHandler);
normalModuleFactory.hooks.parser
.for('javascript/esm')
.tap(this.constructor.name, parserHandler);
}

@@ -416,0 +374,0 @@ );

@@ -1,3 +0,2 @@

const Template = require('webpack/lib/Template');
const { refreshGlobal } = require('../globals');
const { getRefreshGlobalScope } = require('../globals');

@@ -11,22 +10,26 @@ /**

/** @type {RuntimeTemplate} */
const FALLBACK_RUNTIME_TEMPLATE = {
basicFunction(args, body) {
return `function(${args}) {\n${Template.indent(body)}\n}`;
},
supportsConst() {
return false;
},
returningFunction(returnValue, args = '') {
return `function(${args}) { return ${returnValue}; }`;
},
};
/**
* Generates the refresh global runtime template.
* @param {RuntimeTemplate} [runtimeTemplate] The runtime template helpers.
* @param {import('webpack').Template} Template The template helpers.
* @param {Record<string, string>} [RuntimeGlobals] The runtime globals.
* @param {RuntimeTemplate} [RuntimeTemplate] The runtime template helpers.
* @returns {string} The refresh global runtime template.
*/
function getRefreshGlobal(runtimeTemplate = FALLBACK_RUNTIME_TEMPLATE) {
const declaration = runtimeTemplate.supportsConst() ? 'const' : 'var';
function getRefreshGlobal(
Template,
RuntimeGlobals = {},
RuntimeTemplate = {
basicFunction(args, body) {
return `function(${args}) {\n${Template.indent(body)}\n}`;
},
supportsConst() {
return false;
},
returningFunction(returnValue, args = '') {
return `function(${args}) { return ${returnValue}; }`;
},
}
) {
const declaration = RuntimeTemplate.supportsConst() ? 'const' : 'var';
const refreshGlobal = getRefreshGlobalScope(RuntimeGlobals);
return Template.asString([

@@ -39,7 +42,7 @@ `${refreshGlobal} = {`,

// they will be mutated in place during module initialisation by the `setup` function below.
`register: ${runtimeTemplate.returningFunction('undefined')},`,
`signature: ${runtimeTemplate.returningFunction(
runtimeTemplate.returningFunction('type', 'type')
`register: ${RuntimeTemplate.returningFunction('undefined')},`,
`signature: ${RuntimeTemplate.returningFunction(
RuntimeTemplate.returningFunction('type', 'type')
)},`,
`setup: ${runtimeTemplate.basicFunction('currentModuleId', [
`setup: ${RuntimeTemplate.basicFunction('currentModuleId', [
// Store all previous values for fields on `refreshGlobal` -

@@ -60,10 +63,10 @@ // this allows proper restoration in the `cleanup` phase.

Template.indent([
`createSignatureFunctionForTransform: ${runtimeTemplate.returningFunction(
runtimeTemplate.returningFunction('type', 'type')
`createSignatureFunctionForTransform: ${RuntimeTemplate.returningFunction(
RuntimeTemplate.returningFunction('type', 'type')
)},`,
`register: ${runtimeTemplate.returningFunction('undefined')}`,
`register: ${RuntimeTemplate.returningFunction('undefined')}`,
]),
'};',
'',
`${refreshGlobal}.register = ${runtimeTemplate.basicFunction('type, id', [
`${refreshGlobal}.register = ${RuntimeTemplate.basicFunction('type, id', [
`${declaration} typeId = currentModuleId + " " + id;`,

@@ -75,3 +78,3 @@ `${refreshGlobal}.runtime.register(type, typeId);`,

'',
`${refreshGlobal}.cleanup = ${runtimeTemplate.basicFunction('cleanupModuleId', [
`${refreshGlobal}.cleanup = ${RuntimeTemplate.basicFunction('cleanupModuleId', [
// Only cleanup if the module IDs match.

@@ -78,0 +81,0 @@ // In rare cases, it might get called in another module's `cleanup` phase.

const getAdditionalEntries = require('./getAdditionalEntries');
const getIntegrationEntry = require('./getIntegrationEntry');
const getParserHelpers = require('./getParserHelpers');
const getRefreshGlobal = require('./getRefreshGlobal');

@@ -8,2 +7,3 @@ const getSocketIntegration = require('./getSocketIntegration');

const injectRefreshLoader = require('./injectRefreshLoader');
const makeRefreshRuntimeModule = require('./makeRefreshRuntimeModule');
const normalizeOptions = require('./normalizeOptions');

@@ -14,3 +14,2 @@

getIntegrationEntry,
getParserHelpers,
getRefreshGlobal,

@@ -20,3 +19,4 @@ getSocketIntegration,

injectRefreshLoader,
makeRefreshRuntimeModule,
normalizeOptions,
};

@@ -11,4 +11,2 @@ // This is a patch for mozilla/source-map#349 -

const { SourceMapConsumer, SourceNode } = require('source-map');
const { Template } = require('webpack');
const { refreshGlobal } = require('../lib/globals');
const {

@@ -27,10 +25,2 @@ getIdentitySourceMap,

const RefreshSetupRuntimes = {
cjs: Template.asString(`${refreshGlobal}.runtime = require('${RefreshRuntimePath}');`),
esm: Template.asString([
`import * as __react_refresh_runtime__ from '${RefreshRuntimePath}';`,
`${refreshGlobal}.runtime = __react_refresh_runtime__;`,
]),
};
/**

@@ -57,2 +47,14 @@ * A simple Webpack loader to inject react-refresh HMR code into modules.

const { ModuleFilenameHelpers, Template } = this._compiler.webpack || require('webpack');
const RefreshSetupRuntimes = {
cjs: Template.asString(
`__webpack_require__.$Refresh$.runtime = require('${RefreshRuntimePath}');`
),
esm: Template.asString([
`import * as __react_refresh_runtime__ from '${RefreshRuntimePath}';`,
`__webpack_require__.$Refresh$.runtime = __react_refresh_runtime__;`,
]),
};
/**

@@ -65,6 +67,9 @@ * @this {import('webpack').loader.LoaderContext}

async function _loader(source, inputSourceMap) {
const moduleSystem = await getModuleSystem(this, options);
const moduleSystem = await getModuleSystem.call(this, ModuleFilenameHelpers, options);
const RefreshSetupRuntime = RefreshSetupRuntimes[moduleSystem];
const RefreshModuleRuntime = getRefreshModuleRuntime({ const: options.const, moduleSystem });
const RefreshModuleRuntime = getRefreshModuleRuntime(Template, {
const: options.const,
moduleSystem,
});

@@ -71,0 +76,0 @@ if (this.sourceMap) {

const { promises: fsPromises } = require('fs');
const path = require('path');
const { ModuleFilenameHelpers } = require('webpack');

@@ -10,7 +9,8 @@ /** @type {string | undefined} */

* Infers the current active module system from loader context and options.
* @param {import('webpack').loader.LoaderContext} loaderContext The Webpack loader context.
* @this {import('webpack').loader.LoaderContext}
* @param {import('webpack').ModuleFilenameHelpers} ModuleFilenameHelpers Webpack's module filename helpers.
* @param {import('../types').NormalizedLoaderOptions} options The normalized loader options.
* @return {Promise<'esm' | 'cjs'>} The inferred module system.
*/
async function getModuleSystem(loaderContext, options) {
async function getModuleSystem(ModuleFilenameHelpers, options) {
// Check loader options -

@@ -25,3 +25,3 @@ // if `esModule` is set we don't have to do extra guess work.

options.esModule.include &&
ModuleFilenameHelpers.matchPart(loaderContext.resourcePath, options.esModule.include)
ModuleFilenameHelpers.matchPart(this.resourcePath, options.esModule.include)
) {

@@ -32,3 +32,3 @@ return 'esm';

options.esModule.exclude &&
ModuleFilenameHelpers.matchPart(loaderContext.resourcePath, options.esModule.exclude)
ModuleFilenameHelpers.matchPart(this.resourcePath, options.esModule.exclude)
) {

@@ -44,4 +44,4 @@ return 'cjs';

// Check current resource's extension
if (/\.mjs$/.test(loaderContext.resourcePath)) return 'esm';
if (/\.cjs$/.test(loaderContext.resourcePath)) return 'cjs';
if (/\.mjs$/.test(this.resourcePath)) return 'esm';
if (/\.cjs$/.test(this.resourcePath)) return 'cjs';

@@ -52,3 +52,3 @@ // Load users' `package.json` -

try {
const packageJsonPath = require.resolve(path.join(loaderContext.rootContext, 'package.json'));
const packageJsonPath = require.resolve(path.join(this.rootContext, 'package.json'));
const buffer = await fsPromises.readFile(packageJsonPath, { encoding: 'utf-8' });

@@ -55,0 +55,0 @@ const rawPackageJson = buffer.toString('utf-8');

@@ -1,3 +0,1 @@

const { Template } = require('webpack');
/**

@@ -17,6 +15,7 @@ * @typedef ModuleRuntimeOptions {Object}

*
* @param {import('webpack').Template} Webpack's templating helpers.
* @param {ModuleRuntimeOptions} options The refresh module runtime options.
* @returns {string} The refresh module runtime template.
*/
function getRefreshModuleRuntime(options) {
function getRefreshModuleRuntime(Template, options) {
const constDeclaration = options.const ? 'const' : 'var';

@@ -23,0 +22,0 @@ const letDeclaration = options.const ? 'let' : 'var';

{
"name": "@pmmmwh/react-refresh-webpack-plugin",
"version": "0.5.0-beta.9",
"version": "0.5.0-rc.0",
"description": "An **EXPERIMENTAL** Webpack plugin to enable \"Fast Refresh\" (also previously known as _Hot Reloading_) for React components.",

@@ -72,3 +72,3 @@ "keywords": [

"@types/webpack": "^4.41.28",
"babel-jest": "^26.6.3",
"babel-jest": "^27.0.2",
"babel-loader": "^8.1.0",

@@ -82,5 +82,5 @@ "cross-spawn": "^7.0.3",

"get-port": "^5.1.1",
"jest": "^26.4.2",
"jest-circus": "^26.4.2",
"jest-environment-node": "^26.3.0",
"jest": "^27.0.4",
"jest-circus": "^27.0.4",
"jest-environment-node": "^27.0.3",
"jest-junit": "^12.0.0",

@@ -92,7 +92,7 @@ "jest-watch-typeahead": "^0.6.3",

"prettier": "^2.3.0",
"puppeteer": "^8.0.0",
"puppeteer": "^9.1.1",
"react-refresh": "^0.10.0",
"sourcemap-validator": "^2.1.0",
"type-fest": "^1.1.3",
"typescript": "4.2.4",
"typescript": "4.3.2",
"webpack": "^4.46.0",

@@ -138,3 +138,3 @@ "webpack-cli": "^3.3.12",

"resolutions": {
"type-fest": "^1.1.3"
"type-fest": "^1.2.0"
},

@@ -141,0 +141,0 @@ "engines": {

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