UNPKG

7.35 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5// the same as before
6var PREFIX = '__reactstandin__';
7var REGENERATE_METHOD = PREFIX + 'regenerateByEval';
8
9var templateOptions = {
10 placeholderPattern: /^([A-Z0-9]+)([A-Z0-9_]+)$/
11
12 /* eslint-disable */
13};var shouldIgnoreFile = function shouldIgnoreFile(file) {
14 return !!file.split('\\').join('/').match(/node_modules\/(react|react-hot-loader)([\/]|$)/);
15};
16/* eslint-enable */
17
18module.exports = function plugin(args) {
19 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
20
21 // This is a Babel plugin, but the user put it in the Webpack config.
22 if (this && this.callback) {
23 throw new Error('React Hot Loader: You are erroneously trying to use a Babel plugin ' + 'as a Webpack loader. We recommend that you use Babel, ' + 'remove "react-hot-loader/babel" from the "loaders" section ' + 'of your Webpack configuration, and instead add ' + '"react-hot-loader/babel" to the "plugins" section of your .babelrc file. ' + 'If you prefer not to use Babel, replace "react-hot-loader/babel" with ' + '"react-hot-loader/webpack" in the "loaders" section of your Webpack configuration. ');
24 }
25 var t = args.types,
26 template = args.template;
27 var _options$safetyNet = options.safetyNet,
28 safetyNet = _options$safetyNet === undefined ? true : _options$safetyNet;
29
30
31 var buildRegistration = template('reactHotLoader.register(ID, NAME, FILENAME);', templateOptions);
32 var headerTemplate = template('(function () {\n var enterModule = (typeof reactHotLoaderGlobal !== \'undefined\' ? reactHotLoaderGlobal : require(\'react-hot-loader\')).enterModule;\n enterModule && enterModule(module);\n }())', templateOptions);
33 var footerTemplate = template('(function () {\n var leaveModule = (typeof reactHotLoaderGlobal !== \'undefined\' ? reactHotLoaderGlobal : require(\'react-hot-loader\')).leaveModule;\n leaveModule && leaveModule(module);\n }())', templateOptions);
34 var evalTemplate = template('this[key]=eval(code);', templateOptions);
35
36 // We're making the IIFE we insert at the end of the file an unused variable
37 // because it otherwise breaks the output of the babel-node REPL (#359).
38
39 var buildTagger = template(' \n(function () { \n \n var reactHotLoader = (typeof reactHotLoaderGlobal !== \'undefined\' ?reactHotLoaderGlobal : require(\'react-hot-loader\')).default;\n \n if (!reactHotLoader) {\n return;\n }\n\n REGISTRATIONS \n}());\n ', templateOptions);
40
41 // Gather top-level variables, functions, and classes.
42 // Try our best to avoid variables from require().
43 // Ideally we only want to find components defined by the user.
44 function shouldRegisterBinding(binding) {
45 var _binding$path = binding.path,
46 type = _binding$path.type,
47 node = _binding$path.node;
48
49 switch (type) {
50 case 'FunctionDeclaration':
51 case 'ClassDeclaration':
52 case 'VariableDeclaration':
53 return true;
54 case 'VariableDeclarator':
55 {
56 var init = node.init;
57
58 if (t.isCallExpression(init) && init.callee.name === 'require') {
59 return false;
60 }
61 return true;
62 }
63 default:
64 return false;
65 }
66 }
67
68 var REGISTRATIONS = Symbol('registrations');
69 return {
70 visitor: {
71 ExportDefaultDeclaration: function ExportDefaultDeclaration(path, state) {
72 var file = state.file;
73 // Default exports with names are going
74 // to be in scope anyway so no need to bother.
75
76 if (path.node.declaration.id) {
77 return;
78 }
79
80 // Move export default right hand side to a variable
81 // so we can later refer to it and tag it with __source.
82 var id = path.scope.generateUidIdentifier('default');
83 var expression = t.isExpression(path.node.declaration) ? path.node.declaration : t.toExpression(path.node.declaration);
84 path.insertBefore(t.variableDeclaration('const', [t.variableDeclarator(id, expression)]));
85 path.node.declaration = id; // eslint-disable-line no-param-reassign
86
87 // It won't appear in scope.bindings
88 // so we'll manually remember it exists.
89 state[REGISTRATIONS].push(buildRegistration({
90 ID: id,
91 NAME: t.stringLiteral('default'),
92 FILENAME: t.stringLiteral(file.opts.filename)
93 }));
94 },
95
96
97 Program: {
98 enter: function enter(_ref, state) {
99 var scope = _ref.scope;
100 var file = state.file;
101
102 state[REGISTRATIONS] = []; // eslint-disable-line no-param-reassign
103
104 // Everything in the top level scope, when reasonable,
105 // is going to get tagged with __source.
106 /* eslint-disable guard-for-in,no-restricted-syntax */
107 for (var id in scope.bindings) {
108 var binding = scope.bindings[id];
109 if (shouldRegisterBinding(binding)) {
110 state[REGISTRATIONS].push(buildRegistration({
111 ID: binding.identifier,
112 NAME: t.stringLiteral(id),
113 FILENAME: t.stringLiteral(file.opts.filename)
114 }));
115 }
116 }
117 /* eslint-enable */
118 },
119 exit: function exit(_ref2, state) {
120 var node = _ref2.node;
121 var file = state.file;
122
123 var registrations = state[REGISTRATIONS];
124 state[REGISTRATIONS] = [];
125
126 // inject the code only if applicable
127 if (registrations && registrations.length && !shouldIgnoreFile(file.opts.filename)) {
128 if (safetyNet) {
129 node.body.unshift(headerTemplate());
130 }
131 // Inject the generated tagging code at the very end
132 // so that it is as minimally intrusive as possible.
133 node.body.push(t.emptyStatement());
134 node.body.push(buildTagger({ REGISTRATIONS: registrations }));
135 node.body.push(t.emptyStatement());
136
137 if (safetyNet) {
138 node.body.push(footerTemplate());
139 }
140 }
141 }
142 },
143 Class: function Class(classPath) {
144 var classBody = classPath.get('body');
145 var hasRegenerateMethod = false;
146 var hasMethods = false;
147
148 classBody.get('body').forEach(function (path) {
149 var node = path.node;
150
151 // don't apply transform to static class properties
152
153 if (node.static) {
154 return;
155 }
156
157 if (node.key.name !== REGENERATE_METHOD) {
158 hasMethods = true;
159 } else {
160 hasRegenerateMethod = true;
161 }
162 });
163
164 if (hasMethods && !hasRegenerateMethod) {
165 var regenerateMethod = t.classMethod('method', t.identifier(REGENERATE_METHOD), [t.identifier('key'), t.identifier('code')], t.blockStatement([evalTemplate()]));
166
167 classBody.pushContainer('body', regenerateMethod);
168
169 classBody.get('body').forEach(function (path) {
170 var node = path.node;
171
172
173 if (node.key.name === REGENERATE_METHOD) {
174 path.addComment('leading', ' @ts-ignore', true);
175 path.get('body').get('body')[0].addComment('leading', ' @ts-ignore', true);
176 }
177 });
178 }
179 }
180 }
181 };
182};
183
184module.exports.shouldIgnoreFile = shouldIgnoreFile;