DEV Community

Jonas Duri
Jonas Duri

Posted on • Updated on

Deploy Astro site to sub-path

Astro is a static site generator which enables you to use a familiar javascript component architecture while shipping less client-side Javascript.

Problem with Sub-Path deployment

When you are not using a custom domain, Gitlab Pages deploys your website to a sub-path, e.g., http(s)://username.example.io/repository-name/.
Due to an open bug, Astro ignores the buildConfig.site configuration, which is necessary to rewrite all asset paths.

Solution

This is a small script which manually touches all files in the output directory and rewrites the paths. To use the script, copy it to your project’s root folder and name the file postbuild.mjs.

import fs from 'fs'
import path from 'path'
import astroConfig from './astro.config.mjs'


const PUBLIC_DIR = astroConfig.dist || "dist"
const argvs = process.argv.slice(2);

if ((argvs[0] === '--p' || argvs[0] === '-path') && argvs[1]) {
    let files = [];
    const extensions = ['.html', '.css', '.js', '.json']
    const PRODUCTION_URL = argvs[1]


    const replaceUrlsInFiles = function(dirPath, arrayOfFiles) {
        files = fs.readdirSync(dirPath)

        files.forEach(function(file) {
            const current = fs.statSync(dirPath + "/" + file)
            if (current.isDirectory()) {
                replaceUrlsInFiles(dirPath + "/" + file, arrayOfFiles)
            } else {
                const filePath = path.join(
                    path.dirname(
                        (
                            import.meta.url).replace(/file\:/, '')), dirPath, "/", file)
                if (extensions.includes(path.extname(filePath))) {
                    let content = fs.readFileSync(filePath)

                    content = String(content).replace(/src="\//g, `src="${PRODUCTION_URL}`)
                    content = String(content).replace(/href="\//g, `href="${PRODUCTION_URL}`)
                    content = String(content).replace(/url\("\//g, `url("${PRODUCTION_URL}`)

                    content = String(content).replace(/src='\//g, `src='${PRODUCTION_URL}`)
                    content = String(content).replace(/href='\//g, `href='${PRODUCTION_URL}`)
                    content = String(content).replace(/url\('\//g, `url('${PRODUCTION_URL}`)
                    fs.writeFileSync(filePath, content)
                }
            }
        })
    }

    if (PRODUCTION_URL && process.env.NODE_ENV === 'production') {
        replaceUrlsInFiles(PUBLIC_DIR, files)
    } else {
        console.log('skip postbuild')
        process.exit(0)
    }
} else {
    console.error('please provide a path argument "-path", "--p"')
    process.exit(1)
}
Enter fullscreen mode Exit fullscreen mode

You can now use the script as a post-build hook via NPM scripts.

{
    "scripts": {
        "dev": "astro dev",
        "start": "astro dev",
        "build": "astro build",
        "postbuild": "node ./postbuild.mjs -path https://username.example.io/repository-name/",
        "preview": "astro preview"
    },
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

I hope this script helps you out until the bug in Astro is fixed. If you have some time to spare, please consider contributing to Astro :)

Top comments (2)

Collapse
 
wbern profile image
William Bernting • Edited

To cover for relative ./assets paths, I used this instead. You can remove all the String(...).replace in the above code and replace with this (6 to 3 lines by account for single and double-quotes in the same regex).

content = String(content).replace(/src=["'][.]{0,1}\//g, `src="${PRODUCTION_URL}`);
          content = String(content).replace(/href=["'][.]{0,1}\//g, `href="${PRODUCTION_URL}`);
          content = String(content).replace(/url\(["'][.]{0,1}\//g, `url("${PRODUCTION_URL}`);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jonas_duri profile image
Jonas Duri

Great, thanks!