Add word-book practice, iOS app shell, and fix embedded WebView blank screen.

Ship dual-track learning (daily accumulation vs textbook),沪教/商务词书 APIs and UI, native iOS wrapper with bundled H5, and production book import on deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-06-06 21:09:27 +08:00
parent 2fae90b597
commit e76fa586f1
76 changed files with 47488 additions and 445 deletions
+64 -4
View File
@@ -1,8 +1,68 @@
import { defineConfig } from 'vite'
import { defineConfig, type Plugin } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
/** WKWebView 用 file:// 加载时,crossorigin 会导致脚本无法执行、页面空白 */
function stripCrossOriginForIOS(): Plugin {
return {
name: 'strip-crossorigin-ios',
apply: 'build',
enforce: 'post',
transformIndexHtml(html) {
return html.replace(/\s+crossorigin(="[^"]*")?/g, '')
},
}
}
/** iOS 内嵌启动配置:在模块脚本之前注入,避免 file:// 下懒加载 chunk 失败 */
function injectIOSRuntimeBootstrap(): Plugin {
return {
name: 'inject-ios-runtime-bootstrap',
apply: 'build',
transformIndexHtml(html) {
const bootstrap = `<script>
window.__WORDLOOP_RUNTIME__ = {
embedded: true,
iosApp: true,
apiBase: 'https://w.tkmind.cn/api'
};
(function () {
if (!location.hash || location.hash === '#') {
var base = location.href.split('#')[0];
location.replace(base + '#/');
}
})();
</script>`
if (html.includes('__WORDLOOP_RUNTIME__')) return html
const withoutModule = html
.replace(/\s+crossorigin(="[^"]*")?/g, '')
.replace('<script type="module"', '<script')
.replace(/\.\/assets\//g, 'wordloop://app/assets/')
return withoutModule.replace('<script src=', `${bootstrap}\n <script src=`)
},
}
}
export default defineConfig(({ mode }) => ({
base: mode === 'ios' ? './' : '/',
plugins: [
vue(),
...(mode === 'ios' ? [stripCrossOriginForIOS(), injectIOSRuntimeBootstrap()] : []),
],
build: mode === 'ios'
? {
modulePreload: false,
cssCodeSplit: false,
rollupOptions: {
output: {
// WKWebView file:// 下 type=module 常无法执行,改为 IIFE 普通脚本
format: 'iife',
inlineDynamicImports: true,
entryFileNames: 'assets/app.js',
assetFileNames: 'assets/app.[ext]',
},
},
}
: undefined,
server: {
port: 18003,
proxy: {
@@ -12,4 +72,4 @@ export default defineConfig({
},
},
},
})
}))