UNPKG

6.72 kBJavaScriptView Raw
1const utils = require("./utils");
2const { spawn } = require("child_process");
3const { resolve: pathResolve } = require("path");
4const { existsSync } = require("fs");
5const readline = require("readline");
6
7const { messages } = require("../plugins/WatchStateLoggerPlugin");
8const { buildEnvData, debuggingEnabled, getUpdatedEmittedFiles } = require("./utils");
9
10let hasBeenInvoked = false;
11
12let webpackProcesses = {};
13let hasLoggedSnapshotWarningMessage = false;
14
15exports.getWebpackProcesses = function getWebpackProcess() {
16 return webpackProcesses;
17}
18
19exports.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 // Currently externals param is passed only from before-preview-sync hook. This hook is triggered only when `tns preview --bundle` command is executed
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 // Watch opens IPC so we don't mess with the stdin/out/err.
64 // These will notify us for the webpack compilation states.
65 // Enables `childProcess.on("message", msg => ...)` kind of communication.
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
126exports.stopWebpackCompiler = function stopWebpackCompiler($logger, platform) {
127 if (platform) {
128 stopWebpackForPlatform($logger, platform);
129 } else {
130 Object.keys(webpackProcesses).forEach(platform => stopWebpackForPlatform($logger, platform));
131 }
132}
133
134function 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
164function 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
174function stopWebpackForPlatform($logger, platform) {
175 $logger.trace(`Stopping webpack watch for platform ${platform}.`);
176 const webpackProcess = webpackProcesses[platform];
177 if (webpackProcess) {
178 webpackProcess.kill("SIGINT");
179 delete webpackProcesses[platform];
180 }
181}
182