diff --git a/.travis.yml b/.travis.yml
index 5988ad9cb..826a00e14 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,7 +23,7 @@ after_success:
before_deploy:
- npm run build
- - npm run docs
+ - ASSET_PATH=/thema/ npm run docs
deploy:
- provider: script
diff --git a/package.json b/package.json
index ed602062f..30275c03d 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
"build:browser": "webpack --mode production && tsc --emitDeclarationOnly --project tsconfig.browser.json",
"build:lib": "tsc --project tsconfig.lib.json",
"dev": "webpack-dev-server --mode development --hot --open",
- "docs": "npm run build:lib && npm run docs:readme && npm run docs:gallery && npm run docs:app",
+ "docs": "npm run build:browser && npm run docs:readme && npm run docs:gallery && npm run docs:app",
"docs:readme": "ts-node --files src/scripts/readme.ts",
"docs:gallery": "ts-node --files src/scripts/gallery.ts",
"docs:app": "webpack --mode production --env.docs=true",
diff --git a/src/demo/app.tsx b/src/demo/app.tsx
index 73e8019e4..92610415e 100644
--- a/src/demo/app.tsx
+++ b/src/demo/app.tsx
@@ -4,15 +4,6 @@
* Provides an interface for switching of both example and theme.
* Used for human 🤗 user acceptance testing 👍 and robot 🤖
* visual regression testing.
- *
- * For HTML content and Javascript modules,
- * switching is achieved via Parcel's [dynamic importing of modules]
- * (https://parceljs.org/code_splitting.html). Note that this seems to load
- * content for all examples and all themes i.e. it is not truly lazy.
- *
- * For CSS, this `import()` approach did not work, maybe because it loads all the
- * CSS stylesheets into the global DOM. So, we take the approach of
- * enabling/disabling `` elements.
*/
import React from 'react'
diff --git a/src/demo/editor/header.tsx b/src/demo/editor/header.tsx
index b23299ac6..ab6397b7c 100644
--- a/src/demo/editor/header.tsx
+++ b/src/demo/editor/header.tsx
@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom'
import { examples } from '../../examples'
import { getExample, setExample } from '../utils/preview'
import { ViewportToggle } from './viewportToggle'
+import { ASSET_PATH } from '../utils'
interface Props {
exampleContent: string[]
@@ -10,7 +11,7 @@ interface Props {
export const HeaderBase = (): JSX.Element => {
return (
-
+
Thema
diff --git a/src/demo/styles.css b/src/demo/styles.css
index 9cac33191..1d30cab04 100644
--- a/src/demo/styles.css
+++ b/src/demo/styles.css
@@ -134,7 +134,7 @@ main {
text-transform: capitalize;
}
- & > a[href^='/editor?'] {
+ & > a[href*='editor?'] {
order: -1;
display: block;
border-bottom: 1px solid var(--color-neutral-400);
diff --git a/src/demo/templates/template.html b/src/demo/templates/template.html
index 321174c54..87dd25fcd 100644
--- a/src/demo/templates/template.html
+++ b/src/demo/templates/template.html
@@ -47,7 +47,10 @@ Pull Request
-
+
diff --git a/src/demo/utils/index.ts b/src/demo/utils/index.ts
index 27f26f4ab..47be51259 100644
--- a/src/demo/utils/index.ts
+++ b/src/demo/utils/index.ts
@@ -1,5 +1,7 @@
import { translate } from '../../util'
+export const ASSET_PATH = process.env.ASSET_PATH ?? '/'
+
export interface ThemeObject {
[key: string]: string
}
diff --git a/src/demo/utils/preview.ts b/src/demo/utils/preview.ts
index 7216580aa..ef45e0c06 100644
--- a/src/demo/utils/preview.ts
+++ b/src/demo/utils/preview.ts
@@ -1,4 +1,4 @@
-import { keys } from '.'
+import { keys, ASSET_PATH } from '.'
import { examples, resolveExample } from '../../examples'
import { append, create } from '../../util'
@@ -21,7 +21,10 @@ export const setExample = (example: string): void => {
const preview = getPreview()
if (preview !== null && !preview.getAttribute('src')?.includes(example)) {
- preview.setAttribute('src', `/examples/${resolveExample(example)}.html`)
+ preview.setAttribute(
+ 'src',
+ `${ASSET_PATH}examples/${resolveExample(example)}.html`
+ )
}
}
diff --git a/src/demo/utils/theme.ts b/src/demo/utils/theme.ts
index 37b09b1a6..7b2a18026 100644
--- a/src/demo/utils/theme.ts
+++ b/src/demo/utils/theme.ts
@@ -1,4 +1,4 @@
-import { diff, objToVars, ThemeObject } from '.'
+import { diff, objToVars, ThemeObject, ASSET_PATH } from '.'
import { styleEntry, themes } from '../../browser'
import { append, create, prepend } from '../../util'
import { keys } from './index'
@@ -11,7 +11,7 @@ import {
export const getThemeCSS = (theme: string): string => {
const req = new XMLHttpRequest()
- req.open('GET', `/themes/${theme}/styles.css`, false)
+ req.open('GET', `${ASSET_PATH}themes/${theme}/styles.css`, false)
req.send(null)
return req.responseText
}
@@ -35,7 +35,7 @@ export const themeSet = (theme: string): void => {
const themeStyles = create('link')
themeStyles.setAttribute('rel', 'stylesheet')
- themeStyles.setAttribute('href', `/themes/${theme}/${styleEntry}`)
+ themeStyles.setAttribute('href', `${ASSET_PATH}themes/${theme}/${styleEntry}`)
themeStyles.setAttribute('id', 'themaStyles')
const previewDoc = getPreviewDoc()
@@ -62,7 +62,7 @@ export const themeSet = (theme: string): void => {
const themeScript = previewDoc.createElement('script')
themeScript.type = 'text/javascript'
- themeScript.src = `/themes/${theme}/index.js`
+ themeScript.src = `${ASSET_PATH}themes/${theme}/index.js`
themeScript.classList.add('themeScript')
previewDoc.body.appendChild(themeScript)
diff --git a/src/scripts/examples.ts b/src/scripts/examples.ts
index 3a12118f1..1deefa505 100644
--- a/src/scripts/examples.ts
+++ b/src/scripts/examples.ts
@@ -85,29 +85,8 @@ function articleAntibodies(): Promise {
)
}
-/**
- * Transforms implicit relative URLs (`somePath.jpg`) found in the generated example HTML documents, into
- * explicitly relative paths ('./somePath.jpg'). This allows the assets to be discovered inside the Theme Editor iframe.
- */
-const qualifyRelativeUrls = (): void => {
- EXAMPLES.map(example => {
- const filePath = `${ex(example.name)}.html`
- const contents = fs
- .readFileSync(filePath)
- .toString()
- .replace(
- /((?:src|href)=["'])(?!(?:https?)?:\/\/)([^/#.][^'"]+)/gm,
- '$1./$2'
- )
-
- fs.writeFileSync(filePath, contents)
- })
-}
-
// Run each function
-Promise.all(EXAMPLES.map(example => example()))
- .then(() => qualifyRelativeUrls())
- .catch(err => console.error(err))
+Promise.all(EXAMPLES.map(example => example())).catch(err => console.error(err))
// Generate `../examples/examples.ts`
fs.writeFileSync(
diff --git a/src/scripts/gallery.ts b/src/scripts/gallery.ts
index e1fe7ed16..4cf1aa21a 100644
--- a/src/scripts/gallery.ts
+++ b/src/scripts/gallery.ts
@@ -67,7 +67,7 @@ async function generateGallery(): Promise {
theme,
await generateSummary(
theme,
- `/editor?theme=${theme}`,
+ `./editor?theme=${theme}`,
example as Article
)
]
diff --git a/webpack.config.js b/webpack.config.js
index fe1a82b41..0c0ff194f 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -10,6 +10,7 @@ const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
const { DefinePlugin, HotModuleReplacementPlugin } = require('webpack')
const contentSource = 'src'
+const ASSET_PATH = process.env.ASSET_PATH || '/'
// Convert absolute filepaths to project relative ones to use as
// output destinations.
@@ -32,7 +33,9 @@ module.exports = (env = {}, { mode }) => {
const contentBase = isDocs ? 'docs' : 'dist'
const entries = [
- './src/**/*.{css,ts,tsx,ttf,woff,woff2}',
+ './src/**/*.{css,ts,tsx,html,ttf,woff,woff2}',
+ // Template are used as basis for HtmlWebpackPlugin, and should not be used as an entry points
+ '!./src/demo/templates/*',
// Don’t compile test files for package distribution
'!**/*.{d,test}.ts',
// These files make use of Node APIs, and do not need to be packaged for Browser targets
@@ -43,7 +46,7 @@ module.exports = (env = {}, { mode }) => {
// Don’t build HTML demo files for package distribution
...(isDocs || isDevelopment
? ['./src/**/*.{jpg,png,gif}']
- : ['!**/demo/*', '!**/examples/*'])
+ : ['!**/*.html', '!**/demo/*', '!**/examples/*'])
]
const entry = globby.sync(entries).reduce(
@@ -63,7 +66,10 @@ module.exports = (env = {}, { mode }) => {
new HtmlWebpackPlugin({
filename: 'editor/index.html',
template: './src/demo/templates/template.html',
- chunks: ['demo/styles', 'themes/stencila/styles', 'demo/app.tsx']
+ chunks: ['demo/styles', 'themes/stencila/styles', 'demo/app.tsx'],
+ templateParameters: {
+ ASSET_PATH
+ }
}),
new HtmlWebpackPlugin({
filename: 'index.html',
@@ -80,11 +86,12 @@ module.exports = (env = {}, { mode }) => {
return {
entry,
resolve: {
- extensions: ['.ts', '.tsx', '.js', '.css']
+ extensions: ['.ts', '.tsx', '.js', '.css', '.html']
},
mode: mode || 'development',
output: {
path: path.resolve(__dirname, contentBase),
+ publicPath: ASSET_PATH,
filename: '[name].js'
},
devServer: {
@@ -94,6 +101,7 @@ module.exports = (env = {}, { mode }) => {
plugins: [
new CleanWebpackPlugin(),
new DefinePlugin({
+ 'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.VERSION': JSON.stringify(
process.env.VERSION || pkgJson.version
@@ -105,12 +113,6 @@ module.exports = (env = {}, { mode }) => {
// non TypeScript/JavaScript files (i.e. for font and CSS files).
new FileManagerPlugin({
onEnd: {
- copy: [
- {
- source: 'src/examples/*.{html,html.media}',
- destination: `${contentBase}/examples/`
- }
- ],
delete: [
`${contentBase}/**/styles.js`,
`${contentBase}/**/styles.js`,
@@ -134,6 +136,22 @@ module.exports = (env = {}, { mode }) => {
}
},
{ test: /\.ejs$/, loader: 'ejs-loader' },
+ {
+ test: /\.html$/i,
+ // Don't transform HtmlWebpackPlugin generated file
+ exclude: /template\.html$/i,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {
+ name: '[name].[ext]',
+ outputPath: fileLoaderOutputPath
+ }
+ },
+ 'extract-loader',
+ 'html-loader'
+ ]
+ },
{
test: /\.(css)$/,
use: [