【问题标题】:Replace Google Fonts with self hosted fonts用自托管字体替换 Google 字体
【发布时间】:2022-08-06 03:42:23
【问题描述】:

我目前正在移植遗留代码库的一部分,该代码库有 100 多个主题,每个主题都带有自己的 css 文件。这些文件充满了指向 Google 字体的硬编码链接,由于 GDPR,这些链接需要被替换。

是否有某种自动化工具可以扫描这些文件、替换 Google 字体的链接并下载所有资产?我在网上找到了几个半自动化工具,但它们都需要复制和粘贴以及手动下载文件。这对于 2-3 种字体是可以的,但对于数百种字体则不行。有什么建议吗?

  • 考虑到项目结构的差异,我认为不会存在这样的工具。您应该能够毫不费力地实现它,方法是编写一个脚本来查找并用本地路径替换 URL,同时将它们下载到任何合适的目录。如果您可以提供有关项目结构的更多信息,我可能会提供帮助。

标签: google-font-api google-fonts


【解决方案1】:

我付出了一些努力来创建这个 NodeJS 脚本。

此脚本搜索所有 css 文件并提取 woff 字体 url。然后,它将它替换为绝对路径根据它找到的 url 下载文件,还会下载相关目录中的文件,该文件可以在 sn-p 中明确标识,如 fontDownloadDirectoryPath 变量指定的那样。

该脚本可以进一步修改和改进,但截至目前,它在其基本级别提供了所需的功能。

我希望这至少可以作为解决所述问题的起点,或者可以完全用作解决方案,改变很少的变量,因为我对达到这个解决方案所需的东西很少的假设是正确的。

请随意修改,相应地喜欢正则表达式模式以匹配其他内容,在模式中添加一些其他字体类型,添加更多代码以使其更健壮和通用,等等其他可能性。

const path = require('path');
const fs = require('fs');
const https = require("https");

// update assets/css with your css path
const directoryPath = path.join(__dirname, 'assets/css');

let fontDownloadDirectoryPath = path.join(__dirname, 'assets/fonts')
let fontDownloadDirectoryFileFullPath = path.join(__dirname, 'assets/fonts/fontsDownloadUrlList.json')

fs.readdir(directoryPath, function (err, files) {
    //handling error
    if (err) {
        return console.log('Unable to scan directory: ' + err);
    }
    //listing all files using forEach
    files.forEach(function (file) {
        // Do whatever you want to do with the file
        let file_full_path = directoryPath + "/" + file
        fs.readFile(file_full_path, 'utf8', (err, content) => {
            if (err) {
                console.error(err);
                return;
            }
            // console.log(content);// show the content of readed file
            let found = content.match(/url\(['"]([^"']+(woff2|eot|woff|ttf)["'])+\)/gi)
            console.log(file_full_path, found);
            let updated_content = content
            if (found) {
                if (fs.existsSync(fontDownloadDirectoryFileFullPath)) {
                    // enter the code to execute after the folder is there.
                    console.log('file exists')
                    fs.readFile(fontDownloadDirectoryFileFullPath, 'utf8', (err, read_content) => {
                        let read_content_json = JSON.parse(read_content)
                        read_content_json.push(...found)
                        fs.writeFile(fontDownloadDirectoryFileFullPath, JSON.stringify(read_content_json), function () { })
                    })
                } else {
                    fs.writeFile(fontDownloadDirectoryFileFullPath, JSON.stringify(found), function () { })
                }
                console.log(found)
                found.forEach((item) => {
                    let fontFileUrl = item.split("'")[1]
                    let fontFileName = fontFileUrl.split("/")[fontFileUrl.split("/").length - 1]
                    console.log(fontFileUrl, fontFileName)
                    https.get(fontFileUrl, response => {
                        var body = '';
                        var i = 0;
                        response.on('data', function (chunk) {
                            i++;
                            body += chunk;
                            console.log('BODY Part: ' + i);
                        });
                        response.on('end', function () {

                            console.log(body);
                            fs.writeFileSync(fontDownloadDirectoryPath + "/" + fontFileName, body, { encoding: 'utf8', flag: 'w' }, (err) => { console.log(err) })
                            console.log('Finished');
                        });
                    });
                    updated_content = updated_content.replace(item, "url('" + fontDownloadDirectoryPath + "/" + fontFileName + "')")
                })
            } else {
                updated_content = content;
            }

            fs.writeFileSync(file_full_path, updated_content, { encoding: 'utf8', flag: 'w' })
        });

    });
});

我在 root/assets/css 目录中使用了下面带有 styles.css 名称的 css 文件来测试上面的脚本:

@font-face {
font-family: 'BR Firma';
src: url('https://fonts.gstatic.com/s/opensans/v29/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0B4taVQUwaEQbjB_mQ.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;

}

【讨论】:

    【解决方案2】:

    在没有更多关于项目、目录结构等的背景知识的情况下,我将概述目前如何完成该任务:

    1. 如果字体不是从一个主 CSS 文件导入(可能发生),请扫描项目的所有目录或 URL(如果您在本地或远程运行它)。
    2. 获取所有 Google 字体 URL
    3. 下载所有资产(即链接中的字体,也许还有一些图片等)

      因此,尽管您完全可以使用目录在本地执行此操作,但为了简洁起见,我将在此处解释一种使用浏览器执行此操作的方法 - 并且可能更方便 - 使用 Python。我假设您可以访问项目的 URL,ofc。

      1. 您可以关注this approach 来抓取您想要的网址。将站点地图中的列表传递给它,以按顺序浏览所有 URL。然后你可以过滤你得到的list,你只需要考虑谷歌字体,只需添加 in 运算符(如here)分别得到真或假。

         substring = 'https://fonts.googleapis.com'
         if substring in element:
             list.append(element)
         else:
             #do nothing, don't add it to list
        
      2. 现在您应该拥有所有您感兴趣的 URL。如果该项目有多个具有不同字体的 HTML 页面,那么您需要扫描这些页面 - 或者可能只是确定所有这些页面。注意:将列表存储在文件中以进一步将此代码添加到先前的脚本中通常很有用。 More info

            with open('urls.txt', 'w') as f:
                f.write(element)
        
        1. 要下载资产,您可以使用this approach。既然你有所有的 URL,你应该可以。

        差不多就是这样!如果您更深入地了解项目结构,我们可以更精确地完成脚本。此外,您可以在调整脚本时快速使用 Jupyter Notebook 运行脚本。与此同时,需要澄清的公开细节是:

        • 扫描网站或文件?
        • 只有 HTML 文件还是所有项目?
        • 要下载什么?仅字体资产?
        • Python 脚本可以很好地完成这项任务吗?

    【讨论】:

      【解决方案3】:

      任何 IDE 都可以使用适当的模式“在文件中搜索和替换”。 例如:PHPStorm: Find and replace text using regular expressions。单独查找所有出现的事件已经很有价值,并且 IDE 可能有助于“移植遗留代码库的部分”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-12-26
        • 2022-07-02
        • 1970-01-01
        • 2021-04-29
        • 2020-09-06
        • 2014-06-26
        • 1970-01-01
        相关资源
        最近更新 更多