fix: remove invalid iOS web fonts

This commit is contained in:
Tienson Qin
2026-05-10 17:28:10 +08:00
parent 63acfae310
commit f1fa9f3f5d
6 changed files with 126 additions and 36 deletions

View File

@@ -90,6 +90,9 @@ jobs:
- name: Prepare iOS build
run: pnpm exec cap sync ios
- name: Verify iOS web fonts
run: pnpm test:ios-web-fonts
- name: Build and upload iOS app
run: fastlane beta
working-directory: ./ios/App

View File

@@ -21,10 +21,10 @@ const resourceSyncGlobs = [
const outputFilePath = path.join(outputPath, '**')
const rawCopySrc = (globs, options = {}) =>
gulp.src(globs, { encoding: false, ...options })
const removeWoff2FontSources = (cssText) =>
const removeUnsupportedIOSFontSources = (cssText) =>
cssText.
replace(/@font-face\s*{[^{}]*url\(["']?web\/Inter-[^{}]*?\.woff2[^{}]*}\s*/g, '').
replace(/url\((["']?)[^)"']+?\.woff2(?:\?[^)"']*)?\1\)\s*format\((["'])woff2\2\),?/g, '')
replace(/url\((["']?)[^)"']+?\.(?:woff2|woff)(?:\?[^)"']*)?\1\)\s*format\((["'])(?:woff2|woff)\2\),?\s*/g, '')
const staticCleanKeep = new Set([
'entitlements.plist',
'node_modules',
@@ -73,7 +73,7 @@ const css = {
if (fs.existsSync(filePath)) {
fs.writeFileSync(
filePath,
removeWoff2FontSources(fs.readFileSync(filePath, 'utf8')))
removeUnsupportedIOSFontSources(fs.readFileSync(filePath, 'utf8')))
}
}
return Promise.resolve()
@@ -170,7 +170,6 @@ const common = {
'node_modules/inter-ui/inter.css',
]).pipe(gulp.dest(path.join(outputPath, 'mobile', 'css'))),
() => rawCopySrc([
'node_modules/katex/dist/fonts/*.woff',
'node_modules/katex/dist/fonts/*.ttf',
]).pipe(gulp.dest(path.join(outputPath, 'mobile', 'css', 'fonts'))),
)(...params)

View File

@@ -70,7 +70,7 @@
"webpack-app-build": "pnpm exec webpack build --mode production --config-name app",
"webpack-mobile-build": "pnpm exec webpack build --mode production --config-name mobile",
"sync-android-release": "pnpm clean && pnpm release-mobile && rm -rf ./static/mobile/**/*.map && pnpm exec cap sync android",
"sync-ios-release": "pnpm clean && pnpm release-mobile && rm -rf ./static/mobile/**/*.map && pnpm exec cap sync ios",
"sync-ios-release": "pnpm clean && pnpm release-mobile && rm -rf ./static/mobile/**/*.map && pnpm exec cap sync ios && pnpm test:ios-web-fonts",
"clean": "gulp clean",
"test": "run-s cljs:test cljs:run-test",
"test:ios-web-fonts": "node ./scripts/check-ios-web-fonts.mjs",

View File

@@ -1,51 +1,30 @@
import fs from 'node:fs'
import path from 'node:path'
import { findUnsupportedIOSFontAssets } from './lib/check-ios-web-fonts.mjs'
const repoRoot = path.resolve(import.meta.dirname, '..')
const assetRoots = [
path.join(repoRoot, 'static', 'mobile'),
path.join(repoRoot, 'ios', 'App', 'App', 'public'),
]
const existingAssetRoots = assetRoots.filter((root) => fs.existsSync(root))
const result = findUnsupportedIOSFontAssets({ repoRoot, assetRoots })
if (existingAssetRoots.length === 0) {
if (result.roots.length === 0) {
throw new Error('No iOS web assets found. Run pnpm release-mobile or pnpm sync-ios-release first.')
}
const walk = (dir) => {
const entries = fs.readdirSync(dir, { withFileTypes: true })
return entries.flatMap((entry) => {
const fullPath = path.join(dir, entry.name)
return entry.isDirectory() ? walk(fullPath) : fullPath
})
}
const relativePath = (filePath) => path.relative(repoRoot, filePath)
const files = existingAssetRoots.flatMap(walk)
const woff2Files = files
.filter((filePath) => filePath.endsWith('.woff2'))
.map(relativePath)
.sort()
const cssWoff2References = files
.filter((filePath) => filePath.endsWith('.css'))
.flatMap((filePath) => {
const css = fs.readFileSync(filePath, 'utf8')
return css.includes('.woff2') ? [relativePath(filePath)] : []
})
.sort()
if (woff2Files.length > 0) {
console.error('iOS web assets must not include .woff2 font files:')
for (const filePath of woff2Files) {
if (result.fontFiles.length > 0) {
console.error('iOS web assets must not include .woff or .woff2 font files:')
for (const filePath of result.fontFiles) {
console.error(`- ${filePath}`)
}
process.exit(1)
}
if (cssWoff2References.length > 0) {
console.error('iOS web CSS must not reference .woff2 font files:')
for (const filePath of cssWoff2References) {
if (result.cssFiles.length > 0) {
console.error('iOS web CSS must not reference .woff or .woff2 font files:')
for (const filePath of result.cssFiles) {
console.error(`- ${filePath}`)
}
process.exit(1)

View File

@@ -0,0 +1,41 @@
import fs from 'node:fs'
import path from 'node:path'
const unsupportedFontFilePattern = /\.(?:woff2|woff)$/
const unsupportedCssFontPattern = /\.woff2?["')]|\bformat\(["']woff2?["']\)/
const walk = (dir) => {
const entries = fs.readdirSync(dir, { withFileTypes: true })
return entries.flatMap((entry) => {
const fullPath = path.join(dir, entry.name)
return entry.isDirectory() ? walk(fullPath) : fullPath
})
}
const relativePath = (repoRoot, filePath) =>
path.relative(repoRoot, filePath).split(path.sep).join('/')
export const existingAssetRoots = (assetRoots) =>
assetRoots.filter((root) => fs.existsSync(root))
export const findUnsupportedIOSFontAssets = ({ repoRoot, assetRoots }) => {
const roots = existingAssetRoots(assetRoots)
const files = roots.flatMap(walk)
return {
fontFiles: files
.filter((filePath) => unsupportedFontFilePattern.test(filePath))
.map((filePath) => relativePath(repoRoot, filePath))
.sort(),
cssFiles: files
.filter((filePath) => filePath.endsWith('.css'))
.flatMap((filePath) => {
const css = fs.readFileSync(filePath, 'utf8')
return unsupportedCssFontPattern.test(css)
? [relativePath(repoRoot, filePath)]
: []
})
.sort(),
roots,
}
}

View File

@@ -0,0 +1,68 @@
import assert from 'node:assert/strict'
import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import test from 'node:test'
import {
findUnsupportedIOSFontAssets,
} from '../../lib/check-ios-web-fonts.mjs'
test('findUnsupportedIOSFontAssets rejects woff and woff2 files and CSS references', () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'logseq-ios-fonts-'))
const assetRoot = path.join(tempDir, 'public')
const fontDir = path.join(assetRoot, 'css', 'fonts')
fs.mkdirSync(fontDir, { recursive: true })
fs.writeFileSync(path.join(fontDir, 'KaTeX_Main-Regular.ttf'), '')
fs.writeFileSync(path.join(fontDir, 'KaTeX_Main-Regular.woff'), '')
fs.writeFileSync(path.join(fontDir, 'KaTeX_Main-Regular.woff2'), '')
fs.writeFileSync(
path.join(assetRoot, 'css', 'style.css'),
[
'@font-face{src:url(fonts/KaTeX_Main-Regular.woff) format("woff")}',
'@font-face{src:url(fonts/KaTeX_Main-Regular.woff2) format("woff2")}',
'@font-face{src:url(fonts/KaTeX_Main-Regular.ttf) format("truetype")}',
].join('\n'))
try {
const result = findUnsupportedIOSFontAssets({
repoRoot: tempDir,
assetRoots: [assetRoot],
})
assert.deepEqual(result.fontFiles, [
'public/css/fonts/KaTeX_Main-Regular.woff',
'public/css/fonts/KaTeX_Main-Regular.woff2',
])
assert.deepEqual(result.cssFiles, [
'public/css/style.css',
])
} finally {
fs.rmSync(tempDir, { recursive: true, force: true })
}
})
test('findUnsupportedIOSFontAssets accepts ttf-only assets', () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'logseq-ios-fonts-'))
const assetRoot = path.join(tempDir, 'public')
const fontDir = path.join(assetRoot, 'css', 'fonts')
fs.mkdirSync(fontDir, { recursive: true })
fs.writeFileSync(path.join(fontDir, 'KaTeX_Main-Regular.ttf'), '')
fs.writeFileSync(
path.join(assetRoot, 'css', 'style.css'),
'@font-face{src:url(fonts/KaTeX_Main-Regular.ttf) format("truetype")}')
try {
const result = findUnsupportedIOSFontAssets({
repoRoot: tempDir,
assetRoots: [assetRoot],
})
assert.deepEqual(result.fontFiles, [])
assert.deepEqual(result.cssFiles, [])
} finally {
fs.rmSync(tempDir, { recursive: true, force: true })
}
})