1 | const utils = require("./utils");
|
2 | const { spawn } = require("child_process");
|
3 | const { resolve: pathResolve } = require("path");
|
4 | const { existsSync } = require("fs");
|
5 | const readline = require("readline");
|
6 |
|
7 | const { messages } = require("../plugins/WatchStateLoggerPlugin");
|
8 | const { buildEnvData, debuggingEnabled, getUpdatedEmittedFiles } = require("./utils");
|
9 |
|
10 | let hasBeenInvoked = false;
|
11 |
|
12 | let webpackProcesses = {};
|
13 | let hasLoggedSnapshotWarningMessage = false;
|
14 |
|
15 | exports.getWebpackProcesses = function getWebpackProcess() {
|
16 | return webpackProcesses;
|
17 | }
|
18 |
|
19 | exports.runWebpackCompiler = function runWebpackCompiler(config, $projectData, $logger, $liveSyncService, hookArgs) {
|
20 | if (config.bundle) {
|
21 | return new Promise(function (resolveBase, rejectBase) {
|
22 | if (webpackProcesses[config.platform]) {
|
23 | return resolveBase();
|
24 | }
|
25 |
|
26 | let isResolved = false;
|
27 | function resolve() {
|
28 | if (isResolved) return;
|
29 | isResolved = true;
|
30 | resolveBase();
|
31 | }
|
32 | function reject(error) {
|
33 | if (isResolved) return;
|
34 | isResolved = true;
|
35 | rejectBase(error);
|
36 | }
|
37 |
|
38 | console.log(`Running webpack for ${config.platform}...`);
|
39 |
|
40 | const projectDir = $projectData.projectDir;
|
41 | const { platform, env } = config;
|
42 | if (debuggingEnabled($liveSyncService, projectDir)) {
|
43 | env["sourceMap"] = true;
|
44 | }
|
45 |
|
46 |
|
47 | if (hookArgs && hookArgs.externals) {
|
48 | env.externals = hookArgs.externals;
|
49 | }
|
50 |
|
51 | const envData = buildEnvData($projectData, platform, env);
|
52 | const envParams = buildEnvCommandLineParams(config, envData, $logger);
|
53 |
|
54 | const args = [
|
55 | "--preserve-symlinks",
|
56 | pathResolve(projectDir, "node_modules", "webpack", "bin", "webpack.js"),
|
57 | `--config=${pathResolve(projectDir, "webpack.config.js")}`,
|
58 | ...(config.watch ? ["--watch"] : []),
|
59 | ...envParams,
|
60 | ].filter(a => !!a);
|
61 |
|
62 | const childProcess = spawn("node", args, {
|
63 |
|
64 |
|
65 |
|
66 | stdio: config.watch ? ["inherit", "inherit", "inherit", "ipc"] : "inherit",
|
67 | cwd: projectDir
|
68 | });
|
69 |
|
70 | let isFirstWebpackWatchCompilation = true;
|
71 | function resolveOnWebpackCompilationComplete(message) {
|
72 | if (message === messages.compilationComplete) {
|
73 | console.log("Webpack build done!");
|
74 | resolve();
|
75 | }
|
76 |
|
77 | if (message.emittedFiles) {
|
78 | if (isFirstWebpackWatchCompilation) {
|
79 | isFirstWebpackWatchCompilation = false;
|
80 | return;
|
81 | }
|
82 |
|
83 | const result = getUpdatedEmittedFiles(message.emittedFiles);
|
84 |
|
85 | if (hookArgs.hmrData) {
|
86 | hookArgs.hmrData[platform] = {
|
87 | hash: result.hash || "",
|
88 | fallbackFiles: result.fallbackFiles
|
89 | };
|
90 | }
|
91 |
|
92 | if (hookArgs.filesToSyncMap && hookArgs.startSyncFilesTimeout) {
|
93 | hookArgs.filesToSyncMap[platform] = result.emittedFiles;
|
94 | hookArgs.startSyncFilesTimeout(platform);
|
95 | } else if (hookArgs.filesToSync && hookArgs.startSyncFilesTimeout) {
|
96 | hookArgs.filesToSync.push(...result.emittedFiles);
|
97 | hookArgs.startSyncFilesTimeout(platform);
|
98 | }
|
99 | }
|
100 | }
|
101 |
|
102 | if (config.watch) {
|
103 | childProcess.on("message", resolveOnWebpackCompilationComplete);
|
104 | if (webpackProcesses[platform]) {
|
105 | throw new Error("Webpack process already spawned.");
|
106 | }
|
107 | webpackProcesses[platform] = childProcess;
|
108 | }
|
109 |
|
110 | childProcess.on("close", code => {
|
111 | if (webpackProcesses[platform] === childProcess) {
|
112 | delete webpackProcesses[platform];
|
113 | }
|
114 | if (code === 0) {
|
115 | resolve();
|
116 | } else {
|
117 | const error = new Error(`Executing webpack failed with exit code ${code}.`);
|
118 | error.code = code;
|
119 | reject(error);
|
120 | }
|
121 | });
|
122 | });
|
123 | }
|
124 | }
|
125 |
|
126 | exports.stopWebpackCompiler = function stopWebpackCompiler(platform) {
|
127 | if (platform) {
|
128 | stopWebpackForPlatform(platform);
|
129 | } else {
|
130 | Object.keys(webpackProcesses).forEach(platform => stopWebpackForPlatform(platform));
|
131 | }
|
132 | }
|
133 |
|
134 | function buildEnvCommandLineParams(config, envData, $logger) {
|
135 | const envFlagNames = Object.keys(envData);
|
136 | const snapshotEnvIndex = envFlagNames.indexOf("snapshot");
|
137 | if (snapshotEnvIndex > -1 && !utils.shouldSnapshot(config)) {
|
138 | logSnapshotWarningMessage($logger);
|
139 | envFlagNames.splice(snapshotEnvIndex, 1);
|
140 | }
|
141 |
|
142 | const args = [];
|
143 | envFlagNames.map(item => {
|
144 | let envValue = envData[item];
|
145 | if (typeof envValue === "undefined") {
|
146 | return;
|
147 | }
|
148 | if (typeof envValue === "boolean") {
|
149 | if (envValue) {
|
150 | args.push(`--env.${item}`);
|
151 | }
|
152 | } else {
|
153 | if (!Array.isArray(envValue)) {
|
154 | envValue = [envValue];
|
155 | }
|
156 |
|
157 | envValue.map(value => args.push(`--env.${item}=${value}`))
|
158 | }
|
159 | });
|
160 |
|
161 | return args;
|
162 | }
|
163 |
|
164 | function logSnapshotWarningMessage($logger) {
|
165 | if (!hasLoggedSnapshotWarningMessage) {
|
166 | $logger.warn("Stripping the snapshot flag. " +
|
167 | "Bear in mind that snapshot is only available in release builds and " +
|
168 | "is NOT available on Windows systems.");
|
169 |
|
170 | hasLoggedSnapshotWarningMessage = true;
|
171 | }
|
172 | }
|
173 |
|
174 | function stopWebpackForPlatform(platform) {
|
175 | const webpackProcess = webpackProcesses[platform];
|
176 | webpackProcess.kill("SIGINT");
|
177 | delete webpackProcesses[platform];
|
178 | }
|
179 |
|