Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ | Rejoignez-nous sur le Chat 💬

Skip to content
Snippets Groups Projects
build.js 7.66 KiB
Newer Older
  • Learn to ignore specific revisions
  • peter_rabbit's avatar
    peter_rabbit committed
    #!/usr/bin/env node
    
    "use strict";
    
    const fs = require("fs");
    
    const { bundle } = require("simple-browser-js-bundler");
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
    const _dir = process.cwd();
    
    peter_rabbit's avatar
    peter_rabbit committed
    const config = require("./config");
    const build_conf = config.build;
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
    const build_minified = process.argv.includes("prod");
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
    const _path = require("path");
    const parent_dir = _path.join(_dir, "..");
    
    peter_rabbit's avatar
    peter_rabbit committed
    // Handle home page
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
    bundle(`${_dir}/src/main.js`, `${parent_dir}/public/main.js`, { minify: build_minified });
    
    // Handle article-view script
    bundle(`${_dir}/src/article-view.js`, `${parent_dir}/public/article-view.js`, { minify: build_minified });
    
    peter_rabbit's avatar
    peter_rabbit committed
    
    // Handle subpages
    
    peter_rabbit's avatar
    peter_rabbit committed
    function getPageHtml(pageName, pageMeta) {
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
        let html = fs.readFileSync(`${parent_dir}/public/index.html`, "utf-8");
    
    peter_rabbit's avatar
    peter_rabbit committed
        const setMeta = function (metaName, value) {
    
    peter_rabbit's avatar
    peter_rabbit committed
            html = html.replace(
    
    peter_rabbit's avatar
    peter_rabbit committed
                html.match(new RegExp(`<meta\\s*name="${metaName}"[^>]+>`, "g"))[0],
    
    peter_rabbit's avatar
    peter_rabbit committed
                `<meta name="${metaName}" content="${value}"/>`
    
    peter_rabbit's avatar
    peter_rabbit committed
        const setTitle = function () {
            html = html.replace(
                html.match(new RegExp(`<title.+</title>`, "g"))[0],
                `<title>${pageMeta.title}</title>`
    
    peter_rabbit's avatar
    peter_rabbit committed
            );
    
            html = html.replace(
    
    peter_rabbit's avatar
    peter_rabbit committed
                html.match(new RegExp(`<h1.+</h1>`, "g")),
                `<h1 style="visibility: hidden">${pageMeta.title}</h1>`
    
    peter_rabbit's avatar
    peter_rabbit committed
        };
        const setStyleSheet = function () {
    
    peter_rabbit's avatar
    peter_rabbit committed
            html = html.replace(
                html.match(new RegExp(`<link.+/style.css[^>]+>`, "g"))[0],
    
    peter_rabbit's avatar
    peter_rabbit committed
                `<link href="/style/style.css" rel="stylesheet" />`
            );
        };
        const setJs = function () {
    
    peter_rabbit's avatar
    peter_rabbit committed
            html = html.replace(
                html.match(new RegExp(`<script.+main.js.+</script>`, "g"))[0],
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
                `<script type="text/javascript" src="/${pageName}/${pageName}.js"></script>`
    
    peter_rabbit's avatar
    peter_rabbit committed
        const setAdditionalMeta = function (metas) {
    
    peter_rabbit's avatar
    peter_rabbit committed
            html = html.replace(
    
    peter_rabbit's avatar
    peter_rabbit committed
                "</head>",
                `${metas
                    .map(kv => {
                        const [name, content] = kv;
                        return `<meta name="${name}" content="${content}"/>`;
                    })
                    .join("\n")}</head>`
            );
        };
    
    peter_rabbit's avatar
    peter_rabbit committed
        const setOgMeta = function () {
            const pageOgMeta = pageMeta.open_graph || {};
    
            const getOgMetaSearchRegex = function (name) {
                return new RegExp(`<meta\\s*property="og:${name}"[^>]+>`, "g");
            };
            const getDefaultOgMetaContent = function (name) {
                const getRegexMatch = function (source, searchRe) {
                    const m = source.match(searchRe);
                    return m ? m[0] : "";
                };
                return getRegexMatch(
                    getRegexMatch(
                        getRegexMatch(html, getOgMetaSearchRegex(name)),
                        new RegExp(`content=".+"`, "g")
                    ),
                    new RegExp(`".+"`, "g")
                ).replace(/"/g, "");
            };
            const requiredOgMeta = [
                { key: "title", defaultValue: pageMeta.title },
                { key: "description", defaultValue: pageMeta.description },
                {
                    key: "image",
    
    peter_rabbit's avatar
    peter_rabbit committed
                    defaultValue: pageMeta.image || getDefaultOgMetaContent("image"),
    
    peter_rabbit's avatar
    peter_rabbit committed
                },
                {
                    key: "url",
                    defaultValue: (function () {
                        const urlContent = getDefaultOgMetaContent("url");
    
    
                        return `${urlContent}${urlContent.charAt(urlContent.length - 1) !== "/" ? "/" : ""
                            }${pageName}`;
    
    peter_rabbit's avatar
    peter_rabbit committed
                    })(),
                },
                {
                    key: "locale",
                    defaultValue: getDefaultOgMetaContent("locale"),
                },
                // TODO : handle locale:alternate meta tags array
            ];
    
    peter_rabbit's avatar
    peter_rabbit committed
            requiredOgMeta.forEach(entry => {
                const { key, defaultValue } = entry;
                html = html.replace(
                    html.match(getOgMetaSearchRegex(key)),
    
    peter_rabbit's avatar
    peter_rabbit committed
                    (function () {
                        const customValue = pageOgMeta[key];
                        if (!customValue)
                            return `<meta property="og:${key}" content="${defaultValue}"/>`;
                        else {
                            return Array.isArray(customValue)
                                ? customValue
    
                                    .map(alt => `<meta property="og:${key}" content="${alt}"/>`)
                                    .join("\n")
    
    peter_rabbit's avatar
    peter_rabbit committed
                                : `<meta property="og:${key}" content="${customValue}"/>`;
                        }
                    })()
    
    peter_rabbit's avatar
    peter_rabbit committed
                );
            });
    
            const additionalOgMeta = Object.keys(pageMeta.open_graph).filter(
                k => !requiredOgMeta.map(rom => rom.key).includes(k)
            );
    
            if (additionalOgMeta.length > 0) {
                html = html.replace(
                    "</head>",
                    `${additionalOgMeta
    
    peter_rabbit's avatar
    peter_rabbit committed
                        .map(k => `<meta property="og:${k}" content="${pageMeta.open_graph[k]}"/>`)
    
                        .join("\n")}</head>`
                );
            }
    
    peter_rabbit's avatar
    peter_rabbit committed
        };
    
    
        const setJsonLdScript = function () {
            const jsonLd = pageMeta.json_ld;
            html = html.replace(
                html.match(new RegExp(`<script.+json.+>[^<]+</script>`, "g"))[0],
                `<script type="application/ld+json">${JSON.stringify(jsonLd)}</script>`
            );
        };
    
    
    peter_rabbit's avatar
    peter_rabbit committed
        setMeta("description", pageMeta.description);
    
    peter_rabbit's avatar
    peter_rabbit committed
        pageMeta.image && setMeta("image", pageMeta.image);
    
    peter_rabbit's avatar
    peter_rabbit committed
        setTitle();
        setStyleSheet();
        setJs();
        setAdditionalMeta(
    
            Object.entries(pageMeta).filter(kv => !build_conf.default_meta_keys.includes(kv[0]))
    
    peter_rabbit's avatar
    peter_rabbit committed
        );
        setOgMeta();
    
    peter_rabbit's avatar
    peter_rabbit committed
        // set twitter image
        html = html.replace(
            html.match(new RegExp(`<meta\\s*property="twitter:image"[^>]+>`, "g"))[0],
    
            `<meta property="twitter:image" content="${pageMeta.image ||
            html
                .match(new RegExp(`<meta\\s*name="image"[^>]+>`, "g"))[0]
                .match(new RegExp(`content=".+"`, "g"))[0]
                .match(new RegExp(`".+"`, "g"))
                .replace(/"/g, "")
    
    peter_rabbit's avatar
    peter_rabbit committed
            }"/>`
        );
    
    
        setJsonLdScript();
    
    peter_rabbit's avatar
    peter_rabbit committed
        return html;
    
    peter_rabbit's avatar
    peter_rabbit committed
    }
    
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
    function deletePageDirectory(path) {
        try {
            const nestedFiles = fs.readdirSync(path);
            for (const nf of nestedFiles) {
                fs.unlinkSync(`${path}/${nf}`);
            }
            fs.rmdirSync(path);
        } catch (error) {
            console.error(error);
        }
    }
    
    
    function createPages(rootdir, destdir) {
        const pages = fs.readdirSync(rootdir);
    
    peter_rabbit's avatar
    peter_rabbit committed
    
    
        for (const p of pages) {
            const fPath = `${rootdir}/${p}`;
            const targetDirPath = `${destdir}/${p}`;
    
    peter_rabbit's avatar
    peter_rabbit committed
    
    
            if (!fs.existsSync(targetDirPath)) {
                fs.mkdirSync(targetDirPath);
            }
    
    peter_rabbit's avatar
    peter_rabbit committed
    
    
            bundle(fPath, `${targetDirPath}/${p}.js`, { minify: build_minified });
    
    peter_rabbit's avatar
    peter_rabbit committed
    
    
            const page = fs.createWriteStream(`${targetDirPath}/index.html`);
            const pageMeta = JSON.parse(fs.readFileSync(`${fPath}/meta.json`, "utf-8"));
            page.write(getPageHtml(p, pageMeta));
    
            if (fs.existsSync(`${fPath}/subpages`)) {
    
                createPages(`${fPath}/subpages`, targetDirPath);
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
            } else {
                for (const d of fs.readdirSync(targetDirPath).filter(f => {
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
                    return fs.statSync(`${targetDirPath}/${f}`).isDirectory() && !build_conf.protected_dirs.includes(f);
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
                })) {
                    deletePageDirectory(`${targetDirPath}/${d}`)
                }
    
            }
        }
    
        // If pages have been deleted in source, remove them in output directory too.
        for (const dir of fs.readdirSync(destdir).filter(f => {
            if (build_conf.protected_dirs.includes(f)) return false;
            const stats = fs.statSync(`${destdir}/${f}`);
            return stats.isDirectory();
        })) {
            if (!pages.includes(dir)) {
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
                deletePageDirectory(`${destdir}/${dir}`)
    
    peter_rabbit's avatar
    peter_rabbit committed
    }
    
    Pierre Jarriges's avatar
    Pierre Jarriges committed
    createPages(`${_dir}/src/pages`, `${parent_dir}/public`);