Skip to content

Commit

Permalink
fix: start i18n perf fix
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinchappell committed Oct 30, 2024
1 parent 7f3b514 commit 3a6ae42
Show file tree
Hide file tree
Showing 25 changed files with 596 additions and 305 deletions.
110 changes: 109 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@
"vite": "^5.4.8",
"vite-plugin-banner": "^0.8.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.2"
"vite-plugin-html": "^3.2.2",
"vite-plugin-static-copy": "^2.0.0"
},
"dependencies": {
"formeo-i18n": "^2.1.3",
Expand Down
6 changes: 1 addition & 5 deletions src/demo/js/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ export const editorEvents = editor => {
editor.i18n.setLang(value)
}
controlFilter.addEventListener('input', onChangeFilterInput)
if (formeoLocale) {
localeSelect.value = JSON.parse(formeoLocale)
} else {
localeSelect.value = 'en-US'
}
localeSelect.value = formeoLocale || 'en-US'

localeSelect.addEventListener('change', onChangeLocale, false)
}
18 changes: 17 additions & 1 deletion src/demo/js/options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const renderContainer = '.render-form'
export const editorOptions = {
editorContainer,
i18n: {
location: `./assets/lang`,
location: './assets/lang',
},
actions: {
// save: formData => null, // do something on save action
Expand All @@ -32,4 +32,20 @@ export const editorOptions = {
export const renderOptions = {
renderContainer,
external,
elements: {
tinymce: {
dependencies: { js: 'cdnjs.cloudflare.com/ajax/libs/tinymce/4.9.11/tinymce.min.js' },
action: {
onRender: elem => {
if (elem.id) {
const selector = `#${elem.id}`
window.tinymce.remove(selector)
window.tinymce.init({
selector: selector,
})
}
},
},
},
},
}
20 changes: 13 additions & 7 deletions src/lib/js/common/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ class DOM {
* @param {Boolean} isPreview generating element for preview or render?
* @return {Object} DOM Object
*/
create = (elem, isPreview = false) => {
create = (elemArg, isPreview = false) => {
let elem = elemArg
if (!elem) {
return
}
Expand Down Expand Up @@ -216,7 +217,7 @@ class DOM {
// Set the new element's dataset
if (elem.dataset) {
for (const data in elem.dataset) {
if (elem.dataset.hasOwnProperty(data)) {
if (Object.hasOwn(elem.dataset, data)) {
element.dataset[data] = typeof elem.dataset[data] === 'function' ? elem.dataset[data]() : elem.dataset[data]
}
}
Expand Down Expand Up @@ -256,13 +257,18 @@ class DOM {
actionHandler(node, actions) {
const handlers = {
onRender: dom.onRender,
render: dom.onRender,
}
const useCaptureEvts = ['focus', 'blur']
const defaultHandler = event => (node, cb) => node.addEventListener(event, cb, useCaptureEvts.includes(event))

return Object.entries(actions).map(([key, cb]) => {
const action = handlers[key] || defaultHandler(key)
return action(node, cb)
return Object.entries(actions).map(([event, cb]) => {
const cbs = Array.isArray(cb) ? cb : [cb]

return cbs.map(cb => {
const action = handlers[event] || defaultHandler(event)
return action(node, cb)
})
})
}

Expand Down Expand Up @@ -340,7 +346,7 @@ class DOM {
}

// Set element attributes
Object.keys(attrs).forEach(attr => {
for (const attr of Object.keys(attrs)) {
const name = h.safeAttrName(attr)
let value = attrs[attr] || ''

Expand All @@ -366,7 +372,7 @@ class DOM {
element.setAttribute(name, value)
}
}
})
}
}

/**
Expand Down
68 changes: 48 additions & 20 deletions src/lib/js/common/loaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,44 @@ import { noop } from './utils/index.mjs'
/* global fetch */

const loaded = {
js: [],
css: [],
js: new Set(),
css: new Set(),
}

const onLoadStylesheet = (elem, cb) => {
elem.removeEventListener('load', onLoadStylesheet)
elem.rel = 'stylesheet'
cb(elem.src)
}

const onLoadJavascript = (elem, cb) => {
elem.removeEventListener('load', onLoadJavascript)
cb(elem.src)
}

export const insertScript = src => {
return new Promise((resolve, reject) => {
if (loaded.js.includes(src)) {
if (loaded.js.has(src)) {
return resolve(src)
}
loaded.js.add(src)

// Create script element and set attributes
const script = dom.create({
tag: 'script',
attrs: {
type: 'text/javascript',
async: true,
src: `//${this.src}`,
src: `//${src.replace(/^https?:\/\//, '')}`,
},
action: {
load: () => {
loaded.js.push(src)
resolve(src)
},
error: () => reject(new Error(`${this.src} failed to load.`)),
load: () => onLoadJavascript(script, resolve),
error: () => reject(new Error(`${src} failed to load.`)),
},
})

// Append the script to the DOM
const el = document.getElementsByTagName('script')[0]
el.parentNode.insertBefore(script, el)
// Append the script to the document head
document.head.appendChild(script)
})
}

Expand All @@ -43,15 +51,11 @@ export const insertStyle = srcs => {
const promises = srcs.map(
src =>
new Promise((resolve, reject) => {
if (loaded.css.includes(src)) {
if (loaded.css.has(src)) {
return resolve(src)
}
function onLoad() {
this.removeEventListener('load', onLoad)
this.rel = 'stylesheet'
loaded.css.push(src)
resolve(src)
}
loaded.css.add(src)

const styleLink = dom.create({
tag: 'link',
attrs: {
Expand All @@ -60,7 +64,7 @@ export const insertStyle = srcs => {
as: 'style',
},
action: {
load: onLoad,
load: () => onLoadStylesheet(styleLink, resolve),
error: () => reject(new Error(`${this.src} failed to load.`)),
},
})
Expand All @@ -72,6 +76,18 @@ export const insertStyle = srcs => {
return Promise.all(promises)
}

export const insertScripts = srcs => {
srcs = Array.isArray(srcs) ? srcs : [srcs]
const promises = srcs.map(src => insertScript(src))
return Promise.all(promises)
}

export const insertStyles = srcs => {
srcs = Array.isArray(srcs) ? srcs : [srcs]
const promises = srcs.map(src => insertStyle(src))
return Promise.all(promises)
}

export const insertIcons = resp => {
const spritePromise = typeof resp === 'string' ? Promise.resolve(resp) : resp.text()
return spritePromise.then(iconSvgStr => {
Expand Down Expand Up @@ -107,3 +123,15 @@ export const ajax = (file, callback, onError = noop) => {
.catch(err => reject(new Error(onError(err))))
})
}

export const LOADER_MAP = {
js: insertScripts,
css: insertStyles,
}

export const fetchDependencies = dependencies => {
const promises = Object.entries(dependencies).map(([type, src]) => {
return LOADER_MAP[type](src)
})
return Promise.all(promises)
}
Loading

0 comments on commit 3a6ae42

Please sign in to comment.