DEV Community

MartinJ
MartinJ

Posted on • Edited on

NgSysV2-4.3: Automated Svelte Pre-render Builds

This post series is indexed at NgateSystems.com. You'll find a super-useful keyword search facility there too.

Last reviewed: Mar'26

1. Introduction

Post 4.2 floated the concept of pre-rendering a web page. The idea was that if a page never changes (or at least doesn't change too often), then it might as well be converted to HTML during the project's "build".

This is fine, but if the underlying data changes too often, running builds to bring pre-rendered pages up to date manually will become annoying. Automation is surely the answer.

This post describes how you might record thenpm run build and gcloud app deploy commands to run the build/deploy sequence for your webapp in a "script" file. A "script" file is just a text file with a .ps1 extension that can be triggered locally by opening the script for editing and selecting "Terminal/Run active file" from the VSCode menu bar. But, more usefully, it can also be configured to be run automatically by the Windows scheduler.

2. A PowerShell Build/Deploy script

Here's a ps1 script you might use:

$projectId = [myProjectId]
$projectEmail = [myProjectEmail]
$projectPath = [myProjectPath]

# ensure the failure of "build" prevents execution of "deploy"
$ErrorActionPreference = "Stop"

# Define log file path
$logPath = "$projectPath\log.txt"

# Overwrite the current log file with a timestamp at the beginning
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"Log started at $timestamp" | Out-File -FilePath $logPath

# list logged-in accounts so you can check that your project email is present  
gcloud auth list  | Out-File -FilePath $logPath -Append
# assuming that you are logged in, your project email /will/ be 
# included in the list, so make it the "active account"
gcloud config set account $myProjectEmail | Out-File -FilePath $logPath -Append

# Set the project ID
gcloud config set project $projectId  | Out-File -FilePath $logPath -Append

# Redirect output to log file
try {

    cd $projectPath 2>&1 | Out-File -FilePath $logPath -Append

    #Build the app
    npm run build | Out-File -FilePath $logPath -Append

    # Fetch all versions ordered by creation date, excluding the latest 10
    $oldVersions = gcloud app versions list  `
        --sort-by="~version.createTime" `
        --format="value(version.id)" | Select-Object -Skip 10

    # Log the old versions to be deleted
    "Old versions to delete: $($oldVersions -join ', ')" | Out-File -FilePath $logPath -Append

    # Delete the old versions if there are any
    if ($oldVersions.Count -gt 0) {
        try {
         $oldVersions | ForEach-Object {
            gcloud app versions delete --service=default --quiet $_  2>&1 | Out-File -FilePath $logPath -Append
       } 
       } catch {
         "Batch deletion encountered an error: $_" | Out-File -FilePath $logPath -Append
       }
    } else {
        "No old versions to delete. The limit of 10 is not exceeded." | Out-File -FilePath $logPath -Append
    }

    # Deploy the app
    gcloud app deploy "$projectPath\build\app.yaml" --quiet 2>&1 | Out-File -FilePath $logPath -Append

    } catch {
        "An error occurred: $_" | Out-File -FilePath $logPath -Append
}
Enter fullscreen mode Exit fullscreen mode

There's syntax here that won't be fully described until later in this series at Post 10.2, but I think it's fairly easy to see what is going on:

Because you intend to schedule the script automatically, you need to maintain a log file to tell you what went wrong if it encounters an error. This adds much unavoidable"clutter". In the code above, [myProjectId} is your Google projectId - e.g., "svelte-dev-80286" and [myProjectPath] is the full pathname for your VSCode project - e.g., "C:\Users\mjoyc\Desktop\GitProjects\svelte-dev". The output log.txt file built by the Append instructions in the script now ends up in the root of your VSCode project folder.

You might be perplexed by the "list logged-in accounts" section. Although this recognises that you need to be logged in to your Google project account to perform the build, it doesn't actually try to log you in using an embedded password. Think about it - do you really want to build your account password - the keys to your software kingdom - to be embedded in a script file? In any case, gcloud sensibly doesn't provide such a command.

If the script is running on your laptop, you will probably be logged into all your accounts (you'll probably find it sensible to have a different account for each one). But you still need to select one of these as the active one, meaning it is used to direct gcloud operations. The active account is signalled by a star against its entry in the logged-in account list. Although the script can't log you in, it can at least make sure you are active by running the gcloud config set account $myProjectEmail command.

You can test your script file in a VSCode terminal session by opening it in the editor and then selecting "Terminal -> Run Active File". For production purposes, however, you need some automation.

3. Configuring a Windows Schedule to run the PowerShell script

Here's a procedure for registering a Windows Scheduler task to run the build script.

  1. Type "Task Scheduler" in the Windows search bar and open the app.
  2. In the Actions menu, click on “Create a Basic Task”.
  3. Supply a name and description for the task
  4. On the Triggers tab, select the interval you want to run the program, such as “Daily”, “Weekly”, etc.
  5. Specify the start date/time and frequency for the task.
  6. Select the “Start a program” option button.
  7. Now, in the “Start a Program” window: In Program/script: Use "browse" to help you enter the path of pwsh.exe (the terminal shell you use in VSCode - "C:\Program Files\PowerShell\7\pwsh.exe"). In Arguments: Enter the full path of the script. eg: [full path to the script][my script filename].ps1. Set “Start in” to the root address of your project
  8. In the next window, select the checkbox “Open the Properties dialogue for this task when I click Finish”, and click the Finish button.
  9. In the General tab of the properties dialogue, ensure that the “Run when user is logged on or not” and “Run with highest privileges” checkboxes are selected. This ensures you are running the script with Administrator rights.
  10. Click the OK button and confirm your right to save your new scheduler task by responding to a login prompt with your Microsoft username and password.
  11. Test the new task by opening the Task Schedule Library, right-clicking on the task's entry here and selecting "Run"

I use a Windows Scheduler task, created using the above procedure, to run a nightly build of the pre-rendered "ngatesystems.com" keyword-search page. Though new posts are now added only rarely, I'm still making regular edits to existing pages. The nightly run arrangement means the search page is never more than a day behind the live data.

4. When Things Go Wrong - Writing Scripts for Schedulers

The syntax of "shell languages is broadly similar to that of JavaScript. Unless you're going to be doing a lot of work in this area, just use ChatGPT to get an explanation of the mechanics of individual statements. But there are a number of features that are peculiar to the case where you're developing a script specifically for a scheduler. Here they are:

  1. You won't see any output from the Scheduler's terminal session, so you need to "pipe" this into a log file in your project. The --Force flag on the first output command in the script clears any previous content. Subsequent --Append lines are then added sequentially.

  2. A feature of many terminal commands is that at certain points, they're written to halt and request approval before proceeding to some critical process. The idea is to give the user a chance to take stock of a summary of what the job is just about to do and assure themselves that this is really what they want. However, when a job is run automatically by a scheduler, this doesn't make much sense. It seems that you're expected to override this behaviour by including a --quiet flag to the command. Without this, scheduled jobs may simply "hang" in a most perplexing way. In the example above, --quiet flags have been added to both the gcloud app versions delete and gcloud app deploy commands. Problems like this are one reason why scheduler scripts will generally include generous amounts of "logging".

  3. Numerous command shells exist, and they don't all support the same command syntax. My personal choice in VSCode has been the pwsh.exe shell. Whatever you opt for here, it makes sense to ensure that your scheduler uses the same shell. You can specify this in a Scheduler task's "Actions" window (see above for guidance).

  4. The Windows Task Scheduler is a very powerful tool, but its interface is idiosyncratic. The procedure for creating a new task is straightforward, but to edit it later, right-click its entry in the task list and select "properties". You can then select individual windows such as "Actions" (though be prepared to quote your Window password to authenticate field changes- no face-id or pin number here). Another good thing to know is that you can test a task by right-clicking it in the scheduler's list of available scripts and selecting "run". This will ignore whatever scheduling you've specified and fire the script immediately. Finally, to copy a Task, export it and re-import it under a new name.

  5. The sample scheduler script shown above includes a catch-all try/catch block that adds $_, the "error object", to the output log file. This is all very well if someone is looking for errors, but for a serious application, you'd want a positive "heads up" arrangement that sends somebody an email or text alert. In the past, this would have been a trivial task, but "spamming" issues mean that the methods you might have used for this have now all been closed off. For simple cases, the answer might be to use a low-cost system like Pushover. This lets you send text messages to a phone for a one-off payment of just $5. After installing the app on your notification target, you'll receive an email with a "user" key to your registered address. You then need to confirm your address, use the PI tab to "register an API" (just enter an application name), and receive an API "token". You can then use these keys in a curl command submitted via a pwsh terminal script as follows:

} catch {    
    curl.exe -s -o NUL --form-string "priority=1" `
        --form-string "token=aiu7yk ..obfuscated... 5uerqq6ix" `
        --form-string "user=ueczz ..obfuscated... jrv54u22" `
        --form-string "message=Something has gone wrong with your nightly .. run" `
        https://api.pushover.net/1/messages.json
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)