11const Workflow = require ( "@saltcorn/data/models/workflow" ) ;
22const Form = require ( "@saltcorn/data/models/form" ) ;
33const File = require ( "@saltcorn/data/models/file" ) ;
4+ const Plugin = require ( "@saltcorn/data/models/plugin" ) ;
45const db = require ( "@saltcorn/data/db" ) ;
56const { getState } = require ( "@saltcorn/data/db/state" ) ;
67const { spawn } = require ( "child_process" ) ;
78const fs = require ( "fs" ) . promises ;
89const path = require ( "path" ) ;
910
10- const buildMainBundle = async ( buildMode , libPath , libMain ) => {
11+ const buildMainBundle = async ( buildMode , libPath , libMain , timestamp ) => {
1112 getState ( ) . log ( 6 , `spawn ${ buildMode } build of main bundle` ) ;
1213 const tenant = db . getTenantSchema ( ) || "public" ;
1314 return new Promise ( ( resolve , reject ) => {
@@ -23,10 +24,12 @@ const buildMainBundle = async (buildMode, libPath, libMain) => {
2324 `user_lib_main=${ libMain } ` ,
2425 "--env" ,
2526 `tenant_name=${ tenant } ` ,
27+ "--env" ,
28+ `timestamp=${ timestamp } ` ,
2629 ] ,
2730 {
2831 cwd : __dirname ,
29- }
32+ } ,
3033 ) ;
3134 child . stdout . on ( "data" , ( data ) => {
3235 getState ( ) . log ( 5 , data . toString ( ) ) ;
@@ -45,7 +48,12 @@ const buildMainBundle = async (buildMode, libPath, libMain) => {
4548 } ) ;
4649} ;
4750
48- const prepareDirectory = async ( { codeSource, codeLocation, buildMode } ) => {
51+ const prepareDirectory = async ( {
52+ codeSource,
53+ codeLocation,
54+ buildMode,
55+ timestamp,
56+ } ) => {
4957 const userLibPath = async ( source , location ) => {
5058 switch ( source ) {
5159 case "local" :
@@ -64,12 +72,12 @@ const prepareDirectory = async ({ codeSource, codeLocation, buildMode }) => {
6472 const libPath = await userLibPath ( codeSource , codeLocation ) ;
6573 const userLibMain = async ( ) => {
6674 const packageJson = JSON . parse (
67- await fs . readFile ( path . join ( libPath , "package.json" ) , "utf8" )
75+ await fs . readFile ( path . join ( libPath , "package.json" ) , "utf8" ) ,
6876 ) ;
6977 if ( packageJson . main ) return packageJson . main ;
7078 else {
7179 throw new Error (
72- "No main field in package.json, please specify the main file"
80+ "No main field in package.json, please specify the main file" ,
7381 ) ;
7482 }
7583 } ;
@@ -89,27 +97,38 @@ const prepareDirectory = async ({ codeSource, codeLocation, buildMode }) => {
8997 ( await buildMainBundle (
9098 buildMode ,
9199 libPath ,
92- libPath ? await userLibMain ( ) : null
100+ libPath ? await userLibMain ( ) : null ,
101+ timestamp ,
93102 ) ) !== 0
94103 ) {
95104 throw new Error ( "Webpack failed, please check your Server logs" ) ;
96105 }
106+ // remove all main_bundle files except the one with the current timestamp
107+ const files = await fs . readdir ( tenantDir ) ;
108+ for ( const file of files ) {
109+ if ( file . startsWith ( "main_bundle_" ) && ! file . endsWith ( `${ timestamp } .js` ) ) {
110+ await fs . unlink ( path . join ( tenantDir , file ) ) ;
111+ }
112+ }
97113} ;
98114
99115const configuration_workflow = ( ) =>
100116 new Workflow ( {
101117 onDone : async ( context ) => {
102118 const { app_code_source, app_code_path, sc_folder, build_mode } = context ;
119+ const timestamp = new Date ( ) . valueOf ( ) ;
103120 await prepareDirectory ( {
104121 codeSource : app_code_source ,
105122 codeLocation :
106123 app_code_source === "local"
107124 ? app_code_path
108125 : app_code_source === "Saltcorn folder"
109- ? sc_folder
110- : null ,
126+ ? sc_folder
127+ : null ,
111128 buildMode : build_mode ,
129+ timestamp,
112130 } ) ;
131+ context . timestamp = timestamp ;
113132 return context ;
114133 } ,
115134 steps : [
@@ -241,17 +260,31 @@ const routes = ({ app_code_source, app_code_path, sc_folder, build_mode }) => {
241260 getState ( ) . log (
242261 6 ,
243262 `app_code_source: ${ app_code_source } , app_code_path: ${ app_code_path } , ` +
244- `sc_folder: ${ sc_folder } , build_mode: ${ build_mode } , `
263+ `sc_folder: ${ sc_folder } , build_mode: ${ build_mode } , ` ,
245264 ) ;
265+ const timestamp = new Date ( ) . valueOf ( ) ;
246266 await prepareDirectory ( {
247267 codeSource : app_code_source ,
248268 codeLocation :
249269 app_code_source === "local"
250270 ? app_code_path
251271 : app_code_source === "Saltcorn folder"
252- ? sc_folder
253- : null ,
272+ ? sc_folder
273+ : null ,
254274 buildMode : build_mode ,
275+ timestamp,
276+ } ) ;
277+ let plugin = await Plugin . findOne ( { name : "react" } ) ;
278+ if ( ! plugin ) {
279+ plugin = await Plugin . findOne ( {
280+ name : "@saltcorn/react" ,
281+ } ) ;
282+ }
283+ plugin . configuration . timestamp = timestamp ;
284+ await plugin . upsert ( ) ;
285+ getState ( ) . processSend ( {
286+ refresh_plugin_cfg : plugin . name ,
287+ tenant : db . getTenantSchema ( ) ,
255288 } ) ;
256289 res . json ( { notify_success : "Build successful" } ) ;
257290 } ,
@@ -265,26 +298,27 @@ module.exports = {
265298 configuration_workflow,
266299 routes,
267300 viewtemplates : ( cfg ) => [ require ( "./react_view" ) ] ,
268- headers : ( ) => {
301+ headers : ( cfg ) => {
269302 const tenant = db . getTenantSchema ( ) || "public" ;
270303 return [
271304 {
272305 headerTag : `<script>var tenant_name = "${ tenant } ";</script>` ,
273306 } ,
274307 {
275- script : `/plugins/public/react/${ tenant } /main_bundle .js` ,
308+ script : `/plugins/public/react/${ tenant } /main_bundle_ ${ cfg . timestamp } .js` ,
276309 } ,
277310 ] ;
278311 } ,
279312 copilot_skills : ( cfg ) => [ require ( "./copilot-skill" ) ( cfg ) ] ,
280313 onLoad : async ( configuration ) => {
314+ if ( ! require ( "cluster" ) . isMaster ) return ;
281315 try {
282316 const tenant = db . getTenantSchema ( ) || "public" ;
283317 const mainBundlePath = path . join (
284318 __dirname ,
285319 "public" ,
286320 tenant ,
287- `main_bundle. js`
321+ `main_bundle_ ${ configuration . timestamp } . js` ,
288322 ) ;
289323 const mainBundleExists = await fs
290324 . access ( mainBundlePath )
@@ -294,15 +328,29 @@ module.exports = {
294328 getState ( ) . log ( 5 , "Main bundle does not exist, building it now" ) ;
295329 const { app_code_source, app_code_path, sc_folder, build_mode } =
296330 configuration ;
331+ const timestamp = new Date ( ) . valueOf ( ) ;
297332 await prepareDirectory ( {
298333 codeSource : app_code_source ,
299334 codeLocation :
300335 app_code_source === "local"
301336 ? app_code_path
302337 : app_code_source === "Saltcorn folder"
303- ? sc_folder
304- : null ,
338+ ? sc_folder
339+ : null ,
305340 buildMode : build_mode ,
341+ timestamp,
342+ } ) ;
343+ let plugin = await Plugin . findOne ( { name : "react" } ) ;
344+ if ( ! plugin ) {
345+ plugin = await Plugin . findOne ( {
346+ name : "@saltcorn/react" ,
347+ } ) ;
348+ }
349+ plugin . configuration . timestamp = timestamp ;
350+ await plugin . upsert ( ) ;
351+ getState ( ) . processSend ( {
352+ refresh_plugin_cfg : plugin . name ,
353+ tenant : db . getTenantSchema ( ) ,
306354 } ) ;
307355 }
308356 } catch ( e ) {
0 commit comments