WIP: bundled appreader for iOS

Update webpack to bundle fonts and CSS

Remove special font handling

Add package.json

allow setting the article data on window so it can be set in index.html

Add window omnivoreArticle definition

Remove unused dependencies

remove unused copy-webpack plugin dep

Remove unused deps

Handle setting the environment dynamically from Swift

Remove unused deps

Remove more unused deps

Update index, dont use subfolders for fonts

Use a regex to replace font url patterns

Remove local apple changes
This commit is contained in:
Jackson Harper 2022-03-17 12:20:08 -07:00
parent c24bc3b136
commit 059389bbe8
9 changed files with 294 additions and 0 deletions

View file

@ -0,0 +1,16 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript"
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"regenerator": true
}
]
]
}

View file

@ -0,0 +1,3 @@
**/node_modules/*
**/out/*
**/.next/*

View file

@ -0,0 +1,26 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json"
},
"plugins": ["@typescript-eslint", "functional"],
"extends": [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"prettier",
"plugin:functional/no-object-orientation"
],
"root": true,
"env": {
"es6": true,
"browser": true,
"jest": true,
"node": true
},
"ignorePatterns": ["next.config.js", "jest.config.js"],
"rules": {
"functional/no-mixed-type": 0,
"react/react-in-jsx-scope": 0
}
}

9
packages/appreader/additional.d.ts vendored Normal file
View file

@ -0,0 +1,9 @@
export {}
declare global {
interface Window {
omnivoreArticle?: any
omnivoreEnv?: any
fontSize?: number
}
}

View file

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no' />
</head>
<body>
<div id="root">
<!-- {{INJECT_SWIFT_STRING_HERE!!}} -->
<script type="text/javascript">
function loadEnv() {
window.omnivoreEnv = {
"NEXT_PUBLIC_APP_ENV":"local",
"NEXT_PUBLIC_LOCAL_BASE_URL":"http://localhost:3000",
"NEXT_PUBLIC_LOCAL_SERVER_BASE_URL":"http://localhost:4000",
"NEXT_PUBLIC_LOCAL_HIGHLIGHTS_BASE_URL":"http://localhost:4000"
}
}
function loadArticle() {
const CONTENT = `
<div class="page" id="readability-page-1" data-omnivore-anchor-idx="1"><div data-omnivore-anchor-idx="2">
<p data-omnivore-anchor-idx="3">I didn't have time to write a short email so I scheduled a long meeting.</p><p data-omnivore-anchor-idx="4">
<a href="https://twitter.com/jacksonh" data-omnivore-anchor-idx="5">jacksonh</a> Jackson Harper <a href="https://twitter.com/jacksonh/status/1069798258141159425" data-omnivore-anchor-idx="6">December 4, 2018, 3:39 AM UTC</a>
</p></div></div>
`;
window.omnivoreArticle = {
id: "test",
linkId: "test",
slug: "test-slug",
createdAt: new Date().toISOString(),
savedAt: new Date().toISOString(),
url: "https://example.com",
title: "Test Article",
content: CONTENT,
originalArticleUrl: "https://example.com",
contentReader: "WEB",
readingProgressPercent: 0,
readingProgressAnchorIndex: 0,
highlights: [],
}
}
loadEnv()
loadArticle()
</script>
</div>
<script src="bundle.js"></script>
</body>
</html>

View file

@ -0,0 +1,37 @@
{
"name": "@omnivore/appreader",
"version": "1.0.0",
"private": true,
"scripts": {
"build": "webpack --mode production"
},
"dependencies": {
"@omnivore/web": "1.0.0"
},
"devDependencies": {
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2",
"@babel/core": "^7.17.7",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@babel/preset-react": "^7.16.7",
"@babel/preset-typescript": "^7.16.7",
"@babel/runtime": "^7.17.7",
"@types/string-replace-loader": "^2.3.2",
"@types/webpack-bundle-analyzer": "^4.4.1",
"@types/webpack-dev-server": "^4.7.2",
"babel-loader": "^8.2.3",
"css-loader": "^6.7.1",
"eslint-config-next": "12.0.7",
"eslint-plugin-functional": "^4.0.2",
"eslint-plugin-react": "^7.28.0",
"string-replace-loader": "^3.1.0",
"style-loader": "^3.3.1",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-dev-server": "^4.7.4"
},
"volta": {
"node": "14.18.0",
"yarn": "1.22.10"
}
}

View file

@ -0,0 +1,56 @@
import React from "react";
import ReactDOM from "react-dom";
import { Box, VStack } from '@omnivore/web/components/elements/LayoutPrimitives'
import { ArticleContainer } from '@omnivore/web/components/templates/article/ArticleContainer'
import { ArticleAttributes } from "@omnivore/web/lib/networking/queries/useGetArticleQuery";
import '@omnivore/web/styles/globals.css'
import '@omnivore/web/styles/articleInnerStyling.css'
const App = () => {
var themeId = window.localStorage.getItem('theme')
if (themeId) {
document.body.classList.remove(
'theme-default',
'White',
'Gray',
'LightGray',
'Dark'
)
document.body.classList.add(themeId)
}
return (
<>
<Box
css={{
overflowY: 'auto',
height: '100%',
width: '100vw',
}}
>
<VStack
alignment="center"
distribution="center"
className="disable-webkit-callout"
>
<ArticleContainer
viewerUsername="test"
article={window.omnivoreArticle as ArticleAttributes}
scrollElementRef={React.createRef()}
isAppleAppEmbed={true}
highlightBarDisabled={false}
highlightsBaseURL="https://example.com"
fontSize={window.fontSize ?? 18}
margin={0}
/>
</VStack>
</Box>
</>
)
}
ReactDOM.render(
<App />,
document.getElementById("root")
);

View file

@ -0,0 +1,17 @@
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"esModuleInterop": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
},
"include": ["additional.d.ts", "src"]
}

View file

@ -0,0 +1,79 @@
import path from "path"
import glob from 'glob'
import { DefinePlugin } from 'webpack'
import { Configuration } from "webpack"
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
const analyze = process.env.ANALYZE
const config: Configuration = {
entry: {
bundle: './src/index.tsx',
fonts: [
...glob.sync('../web/public/static/fonts/Inter/*'),
...glob.sync('../web/public/static/fonts/SFMono/*')
],
},
module: {
rules: [
{
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [
"@babel/preset-env",
["@babel/preset-react", {"runtime": "automatic"}],
"@babel/preset-typescript",
],
},
},
},
{
test: /\.css$/i,
use: ['style-loader', {
loader: 'css-loader',
options: { url: false }
}, {
// We want paths like `/static/fonts/Inter/Inter.woff2 to become
// `Inter.woff2` which is how they will be bundled on iOS.
loader: 'string-replace-loader',
options: {
search: '\(\'/static/fonts/.*/(.*)\'\)',
replace(_s: string, _p: string, group: string) {
return group
},
flags: 'g',
},
}],
},
{
test: /.(ttf|otf|woff(2)?)(\?[a-z0-9]+)?$/,
type: 'asset/resource',
generator: {
filename: '[path][name][ext]'
}
},
],
},
plugins: [
new DefinePlugin({
'process.env': 'window.omnivoreEnv',
}),
new BundleAnalyzerPlugin({
openAnalyzer: !!analyze,
analyzerMode: 'static',
})
],
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
output: {
path: path.resolve(__dirname, "build"),
filename: '[name].js',
},
};
export default config;