This repository was archived by the owner on May 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathplugin.js
136 lines (119 loc) · 4.57 KB
/
plugin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
const fork = require('child_process').fork;
const path = require('path');
const reactDocs = require('react-docgen');
const isString = require('lodash/isString');
const isNaN = require('lodash/isNaN');
const defaults = require('lodash/defaults');
// const readMultipleFiles = require('read-multiple-files');
const carteBlancheResolver = require('./resolver.js').default;
function ReactPlugin(options) {
// Make sure the plugin was instantiated as a constructor, i.e. new ReactPlugin()
if (!(this instanceof ReactPlugin)) {
throw new Error(
'The ReactPlugin must be instantiated with the "new" keyword, i.e. "new ReactPlugin()"\n\n'
);
}
this.options = options || {};
// The hostname option must be a string
if (this.options.hostname && !isString(this.options.hostname)) {
throw new Error('The "hostname" option of the ReactPlugin must be a string!\n\n');
}
const parsedPort = parseFloat(this.options.port);
// The port option must be something that can be made a number
if (this.options.port && isNaN(parsedPort)) {
throw new Error('The "port" option of the ReactPlugin must be a number!\n\n');
}
// If the port can be interpreted as a number, it must be above 0 and below 65535
if (parsedPort < 0 || parsedPort > 65535) {
throw new Error('The "port" must be between 0 and 65535 (inc)!\n\n');
}
// The variationFolderName option must be a string
if (this.options.variationFolderName && !isString(this.options.variationFolderName)) {
throw new Error(
'The "variationFolderName" option of the ReactPlugin must be a string!\n\n'
);
}
// The files option must be an Array or a String
if (this.options.files
&& !isString(this.options.files)
&& (!Array.isArray(this.options.files))) {
throw new Error(
'The "files" option of the ReactPlugin must be an array!\n\n'
);
}
// The injectTags option must be an Array or a String
if (this.options.injectTags && (!Array.isArray(this.options.injectTags))) {
throw new Error(
'The "injectTags" option of the ReactPlugin must be an array!\n\n'
);
}
}
/**
* Kill a Node.js process
*/
function killProcess(proc, err) {
proc.kill('SIGINT');
if (err) {
console.log('Uncaught Exception...'); // eslint-disable-line no-console
console.log(err.stack); // eslint-disable-line no-console
process.exit(1);
} else {
process.exit();
}
}
/**
* Initializes the plugin, called after the main CarteBlanche function above
*/
ReactPlugin.prototype.apply = function apply(compiler) {
// Default options
const options = defaults({}, this.options, {
hostname: 'localhost',
files: [],
injectTags: [],
// The default port is not really used by a popular service:
// https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
port: 8082,
variationFolderName: 'variations',
});
const projectBasePath = compiler.options.context;
const variationBasePath = path.join(projectBasePath, options.variationFolderName);
options.variationBasePath = variationBasePath;
const server = fork(path.join(__dirname, './server/run.js'), [
projectBasePath, // process.argv[2]
JSON.stringify(options), // process.argv[3]
]);
// Prevent the process from exiting immediately
process.stdin.resume();
// When the plugin exits for any reason, kill the forked Node.js process
// with the server. (exit = process.exit(), SIGINT = CTRL+C, uncaughtException =
// error in the code)
process.on('exit', killProcess.bind(null, server));
process.on('SIGINT', killProcess.bind(null, server));
process.on('uncaughtException', killProcess.bind(null, server));
compiler.plugin('compilation', (compilation) => {
// Expose the react parse result to all other carte-blanche plugins
compilation.plugin(
'carte-blanche-plugin-before-processing',
(data) => {
// eslint-disable-next-line no-param-reassign
data.reactDocs = reactDocs.parse(data.source, carteBlancheResolver);
// eslint-disable-next-line no-param-reassign
data.publicPath = compiler.options.output.publicPath;
}
);
// The source carte-blanche plugin
compilation.plugin(
'carte-blanche-plugin-processing',
(renderToClient) => {
renderToClient({
// TODO the name is used in the iframe & playground list
// best to pass it in there instead of hardcoding it
name: 'react',
frontendData: { options },
frontendPlugin: `${require.resolve('./frontend/index.js')}`, // eslint-disable-line global-require,max-len
});
}
);
});
};
module.exports = ReactPlugin;