TASK: #104293 - add clock widgets for homescreen
This commit is contained in:
parent
896cf24e2c
commit
b0fa69bbce
|
@ -0,0 +1,12 @@
|
||||||
|
#! /bin/bash -e
|
||||||
|
|
||||||
|
cmd_run() {
|
||||||
|
./node_modules/.bin/vite build --config ./widgets.config.ts
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_particular() {
|
||||||
|
export WIDGET_FILE_NAME=${@:1}
|
||||||
|
cmd_run
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_particular $@
|
|
@ -13,7 +13,8 @@
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "yarn run esbuild:ts && yarn run build:ts",
|
"build": "yarn run esbuild:ts && yarn run build:ts",
|
||||||
"build:ts": "yarn tsc --build tsconfig-all.json",
|
"build:ts": "yarn tsc --build tsconfig-all.json",
|
||||||
"build:vite": "tsc && vite build",
|
"build:vite": "vite build",
|
||||||
|
"build:widgets": "bin/build-widget",
|
||||||
"esbuild:ts": "node ./tasks/esbuild-packages.js",
|
"esbuild:ts": "node ./tasks/esbuild-packages.js",
|
||||||
"format": "npm run format:prettier",
|
"format": "npm run format:prettier",
|
||||||
"format:prettier": "prettier \"**/*.{cjs,html,js,json,md,ts}\" --write"
|
"format:prettier": "prettier \"**/*.{cjs,html,js,json,md,ts}\" --write"
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
import GaiaWidget from '../gaia-widget'
|
||||||
|
import '../../components/clock/clock'
|
||||||
|
import {StarClock} from '../../components/clock/clock'
|
||||||
|
import {customElement} from 'lit/decorators.js'
|
||||||
|
|
||||||
|
@customElement('gaia-clock')
|
||||||
|
class ClockWidget extends GaiaWidget {
|
||||||
|
_type: 'transparent' | 'daile' = 'daile'
|
||||||
|
|
||||||
|
get type() {
|
||||||
|
return this._type
|
||||||
|
}
|
||||||
|
|
||||||
|
set type(value: 'transparent' | 'daile') {
|
||||||
|
if (value !== this._type) {
|
||||||
|
this._type = value
|
||||||
|
this.clock.type = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
url,
|
||||||
|
appName,
|
||||||
|
origin,
|
||||||
|
size,
|
||||||
|
manifestWidgetName,
|
||||||
|
}: {
|
||||||
|
url: string
|
||||||
|
size: [number, number]
|
||||||
|
origin: string
|
||||||
|
appName: string
|
||||||
|
manifestWidgetName: string
|
||||||
|
}) {
|
||||||
|
super({
|
||||||
|
url: url || 'js/widgets/clock.js',
|
||||||
|
appName: appName || 'homescreen',
|
||||||
|
origin: origin || 'http://homescreen.localhost/manifest.webmanifest',
|
||||||
|
size: size || [2, 2],
|
||||||
|
manifestWidgetName: manifestWidgetName || 'clock',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {}
|
||||||
|
|
||||||
|
clock!: StarClock
|
||||||
|
connectedCallback() {
|
||||||
|
this.clock = this.shadowRoot!.querySelector('star-clock')!
|
||||||
|
this.clock.date = new Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.clock.date = new Date()
|
||||||
|
}
|
||||||
|
get template() {
|
||||||
|
return `
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<star-clock type="diale"></star-clock>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ClockWidget
|
|
@ -0,0 +1,433 @@
|
||||||
|
// import {html, LitElement, css} from 'lit'
|
||||||
|
// import {customElement} from 'lit/decorators.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主屏小组件:
|
||||||
|
*
|
||||||
|
* const widget = new GaiaWidget({
|
||||||
|
* url: 'http://rigesterapp.localhost/widget/a_widget.html',
|
||||||
|
* size: manifest.b2g_features.widget.a_widget.size || [1, 1],
|
||||||
|
* origin: 'http://rigesterapp.localhost',
|
||||||
|
* appName: 'rigesterapp'
|
||||||
|
* manifestWidgetName: 'test-widget'
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* 向注册小组件的应用发送Activity请求:
|
||||||
|
* new WebActivity(activityName, {
|
||||||
|
* data: {
|
||||||
|
* widgetTitle, // 组件名,写在小组件页面的 title 标签内
|
||||||
|
* manifestName, // 清单内的组件名,写在清单文件的 widget 对象中
|
||||||
|
* viewName, // 视图名,写在 template 标签内
|
||||||
|
* },
|
||||||
|
* type: ['widget']
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* TBD:
|
||||||
|
* 1. 多视图功能,每个视图由 <template name="view-name"></template> 包裹,与单视图
|
||||||
|
* 写法(没有 <template> 标签)互斥
|
||||||
|
*/
|
||||||
|
// @customElement('gaia-widget')
|
||||||
|
export default class GaiaWidget extends HTMLElement {
|
||||||
|
url!: string
|
||||||
|
size!: [number, number]
|
||||||
|
origin!: string
|
||||||
|
appName!: string
|
||||||
|
manifestWidgetName!: string // 清单文件中的组件名
|
||||||
|
widgetTitle: string = '' // 组件名
|
||||||
|
viewName: string = '' // 视图名,当该组件有多个视图时,视图名用于区分
|
||||||
|
createTime: number = new Date().getTime()
|
||||||
|
container!: HTMLElement
|
||||||
|
activityRequestTimer: number | undefined
|
||||||
|
constructor({
|
||||||
|
url,
|
||||||
|
size,
|
||||||
|
origin,
|
||||||
|
appName,
|
||||||
|
manifestWidgetName,
|
||||||
|
}: {
|
||||||
|
url: string
|
||||||
|
size: [number, number]
|
||||||
|
origin: string
|
||||||
|
appName: string
|
||||||
|
manifestWidgetName: string
|
||||||
|
}) {
|
||||||
|
super()
|
||||||
|
this.widgetTitle = ''
|
||||||
|
this.manifestWidgetName = manifestWidgetName
|
||||||
|
this.viewName = ''
|
||||||
|
this.createTime = new Date().getTime()
|
||||||
|
this.url = url // 组件文件地址
|
||||||
|
this.origin = origin // 注册应用 origin
|
||||||
|
this.size = size // 组件行列大小
|
||||||
|
this.appName = appName
|
||||||
|
this.attachShadow({mode: 'open'})
|
||||||
|
this.shadowRoot!.innerHTML = this.template
|
||||||
|
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// 补全小组件入口地址
|
||||||
|
if (!/^http(s)?:\/\//.test(this.url)) {
|
||||||
|
if (/^\//.test(this.url)) {
|
||||||
|
this.url = this.origin + this.url
|
||||||
|
} else {
|
||||||
|
this.url = this.origin + '/' + this.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.container = this.shadowRoot!.querySelector(
|
||||||
|
'#gaia-widget-container-' + this.createTime
|
||||||
|
)!
|
||||||
|
this.container.addEventListener('touchstart', this)
|
||||||
|
this.container.addEventListener('touchmove', this)
|
||||||
|
this.container.addEventListener('touchend', this)
|
||||||
|
this.container.addEventListener('click', this)
|
||||||
|
|
||||||
|
// 需要在构造函数中被调用,在connectedCallback中调用会导致移动元素时刷新的问题
|
||||||
|
this.querySources(this.url)
|
||||||
|
// @ts-ignore
|
||||||
|
.then(this.parseHTML)
|
||||||
|
.then(() => {
|
||||||
|
// 防止安装、更新应用时,首次 Activity 请求因注册方 Service Worker 未完成安装而丢失
|
||||||
|
let n = 0
|
||||||
|
this.activityRequestTimer = window.setInterval(() => {
|
||||||
|
if (n++ > 4) clearInterval(this.activityRequestTimer)
|
||||||
|
this.openActivity({data: {type: 'ready'}})
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
.catch((err) => console.error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh(widgetInfo: {size: [number, number]; url: string}) {
|
||||||
|
if (
|
||||||
|
this.size[0] != widgetInfo.size[0] ||
|
||||||
|
this.size[1] != widgetInfo.size[1]
|
||||||
|
) {
|
||||||
|
// 更新后的组件大小发生了变化
|
||||||
|
this.dispatchEvent(new CustomEvent('widget-resize'))
|
||||||
|
}
|
||||||
|
|
||||||
|
this.url = widgetInfo.url
|
||||||
|
this.shadowRoot!.innerHTML = this.template
|
||||||
|
this.container.removeEventListener('touchstart', this)
|
||||||
|
this.container.removeEventListener('touchmove', this)
|
||||||
|
this.container.removeEventListener('touchend', this)
|
||||||
|
this.container.removeEventListener('click', this)
|
||||||
|
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
touchTimer: number | undefined
|
||||||
|
handleEvent(event: TouchEvent) {
|
||||||
|
switch (event.type) {
|
||||||
|
case 'touchstart':
|
||||||
|
console.log(event)
|
||||||
|
clearTimeout(this.touchTimer)
|
||||||
|
this.touchTimer = window.setTimeout(() => {
|
||||||
|
console.log('touchTimer end')
|
||||||
|
this.touchTimer = undefined
|
||||||
|
}, 100)
|
||||||
|
break
|
||||||
|
case 'touchmove':
|
||||||
|
break
|
||||||
|
case 'touchend':
|
||||||
|
case 'click':
|
||||||
|
console.log(this.touchTimer)
|
||||||
|
// @ts-ignore
|
||||||
|
this.touchTimer && this.dispatch(event)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toCamelCase = (string: string) => {
|
||||||
|
// @ts-ignore
|
||||||
|
return string.replace(/\-(.)/g, function replacer(str, p1) {
|
||||||
|
return p1.toUpperCase()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向注册应用发送事件
|
||||||
|
*/
|
||||||
|
dispatch = (event: CustomEvent) => {
|
||||||
|
// @ts-ignore
|
||||||
|
if (!WebActivity) {
|
||||||
|
return console.error('WebActivity is not defined!')
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = this.wrapEvent(event)
|
||||||
|
this.openActivity({data})
|
||||||
|
}
|
||||||
|
|
||||||
|
openActivity = ({data}: any) => {
|
||||||
|
data.widgetTitle = this.widgetTitle
|
||||||
|
data.manifestName = this.manifestWidgetName
|
||||||
|
data.viewName = this.viewName
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const activity = new WebActivity(
|
||||||
|
`${this.appName}_${this.manifestWidgetName}`,
|
||||||
|
{data, type: ['widget']}
|
||||||
|
)
|
||||||
|
|
||||||
|
activity
|
||||||
|
.start()
|
||||||
|
.then((result: any) => {
|
||||||
|
if (this.activityRequestTimer) clearInterval(this.activityRequestTimer)
|
||||||
|
this.handleActivity(result)
|
||||||
|
})
|
||||||
|
.catch((err: any) => console.log(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapEvent = (event: any) => {
|
||||||
|
const target = event?.path?.[0] || event.originalTarget
|
||||||
|
const style: {[prop: string]: string} = {}
|
||||||
|
for (let index = 0; index < target.style.length; index++) {
|
||||||
|
const styleName = target.style.item(index)
|
||||||
|
const camelName = this.toCamelCase(styleName)
|
||||||
|
style[styleName] = target.style[camelName]
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
timeStamp: event.timeStamp,
|
||||||
|
type: event.type,
|
||||||
|
id: target.id,
|
||||||
|
className: target.className,
|
||||||
|
classList: target.classList,
|
||||||
|
dataset: target.dataset,
|
||||||
|
style,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求组件资源
|
||||||
|
*/
|
||||||
|
querySources(url: string) {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
// @ts-ignore
|
||||||
|
const xhr = new XMLHttpRequest({mozSystem: true})
|
||||||
|
xhr.open('GET', url, true)
|
||||||
|
// xhr.responseType = "text";
|
||||||
|
xhr.send()
|
||||||
|
xhr.onload = () => {
|
||||||
|
if (xhr.status == 200) {
|
||||||
|
if (!xhr.response) {
|
||||||
|
rej(
|
||||||
|
new Error(
|
||||||
|
'Empty response to ' + url + ', ' + 'possibly syntax error'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
res(xhr.response)
|
||||||
|
} else {
|
||||||
|
rej(
|
||||||
|
new Error(
|
||||||
|
`query soures err! xhr.status: ${xhr.status}; xhr.url: ${url}`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将文档字符串转化为 DOM 节点
|
||||||
|
* TBD:当前一个组件仅能有一个视图,需要添加多视图情况
|
||||||
|
* @param {DOMString} html 文档字符串
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
parseHTML = (html: string) => {
|
||||||
|
html = this.handleSource(this.filterDom(html))
|
||||||
|
|
||||||
|
const parse = new DOMParser()
|
||||||
|
const htmlDocument = parse.parseFromString(html, 'text/html')
|
||||||
|
const {head, body} = htmlDocument
|
||||||
|
// @ts-ignore
|
||||||
|
this.widgetTitle = head?.querySelector('title').innerHTML
|
||||||
|
if (this.widgetTitle === void 0) {
|
||||||
|
throw new Error('There is not a widget name yet!')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.appendStyle(htmlDocument)
|
||||||
|
this.container.innerHTML = body.innerHTML
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理来自注册应用的 Activity 传入的操作命令
|
||||||
|
*/
|
||||||
|
handleActivity = (data: any) => {
|
||||||
|
const {changeContext, changeAttributes} = data
|
||||||
|
|
||||||
|
this.changeAttributes(changeAttributes)
|
||||||
|
this.changeContext(changeContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
changeContext = (data: any) => {
|
||||||
|
if (!data) return
|
||||||
|
|
||||||
|
data.forEach((operator: any) => {
|
||||||
|
const dom = this.shadowRoot!.querySelector(operator.target)
|
||||||
|
dom.innerText = operator.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过 setAttribute 改变指定元素的属性
|
||||||
|
*/
|
||||||
|
changeAttributes = (data: any) => {
|
||||||
|
if (!data) return
|
||||||
|
|
||||||
|
data.forEach((operator: any) => {
|
||||||
|
if (operator?.data?.length !== 2) throw new Error('Illegal parameter')
|
||||||
|
|
||||||
|
const dom = this.shadowRoot!.querySelector(operator.target)
|
||||||
|
|
||||||
|
if (operator.data[0] === 'src' && !/^http:\/\//.test(operator.data[1])) {
|
||||||
|
let str = operator.data[1].replace(/^\//, '')
|
||||||
|
operator.data[1] = this.origin + '/' + str
|
||||||
|
}
|
||||||
|
dom.setAttribute(...operator.data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TBD: 需要考虑更多元素
|
||||||
|
* 处理img资源请求路径
|
||||||
|
*/
|
||||||
|
handleSource = (html: string) => {
|
||||||
|
html = html.replace(
|
||||||
|
/<img.*?src="(.*?)"/g,
|
||||||
|
(string: string, url: string) => {
|
||||||
|
if (!/^http:\/\//.test(url)) {
|
||||||
|
string = string.replace(url, `${this.origin}/${url}`)
|
||||||
|
}
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定元素内的style标签和[rel="stylesheet"]标签的样式
|
||||||
|
* 加载并添加进影子节点内
|
||||||
|
*/
|
||||||
|
appendStyle = (dom: Document) => {
|
||||||
|
this.collectStyle(dom).then((styles) => {
|
||||||
|
for (const style of styles) {
|
||||||
|
this.shadowRoot!.appendChild(style)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收集指定元素内的style标签和[rel="stylesheet"]标签
|
||||||
|
*/
|
||||||
|
collectStyle(dom: any): Promise<HTMLStyleElement[]> {
|
||||||
|
return new Promise((res) => {
|
||||||
|
let promises: Promise<any>[] = []
|
||||||
|
let styles = [...dom.querySelectorAll('style')] || []
|
||||||
|
const links = dom.querySelectorAll('[rel="stylesheet"]')
|
||||||
|
|
||||||
|
if (links?.length) {
|
||||||
|
links.forEach((element: HTMLLinkElement) => {
|
||||||
|
let href = element.href
|
||||||
|
// 将href的源改为注册组件的源
|
||||||
|
href = href.replace(location.origin, this.origin)
|
||||||
|
if (!/^http:\/\//.test(href)) {
|
||||||
|
href = `${this.origin}/${href}`
|
||||||
|
}
|
||||||
|
promises.push(this.querySources(href))
|
||||||
|
})
|
||||||
|
|
||||||
|
Promise.all(promises).then((sheets) => {
|
||||||
|
for (const css of sheets) {
|
||||||
|
const style = document.createElement('style')
|
||||||
|
style.innerHTML = this.modifyCss(css)
|
||||||
|
styles.push(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
res(styles)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
for (const style of styles) {
|
||||||
|
style.innerHTML = this.modifyCss(style.innerHTML)
|
||||||
|
}
|
||||||
|
|
||||||
|
res(styles)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 html body 样式,并将其样式转为对该组件的样式
|
||||||
|
*/
|
||||||
|
modifyCss = (css: string) => {
|
||||||
|
return css.replace(
|
||||||
|
/([^{]+)(\{[^}]+\})/g,
|
||||||
|
// @ts-ignore
|
||||||
|
(group, selector, declarations) => {
|
||||||
|
selector = selector.replace(
|
||||||
|
/(?<!=[a-zA-Z]|-)(html|body)(?!=[a-zA-Z]|-)/g,
|
||||||
|
// @ts-ignore
|
||||||
|
(selecor, str) => {
|
||||||
|
return `#gaia-widget-container-${this.createTime}`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return selector + declarations
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 筛除 a、script 标签,更改 form 标签的 action 属性
|
||||||
|
*/
|
||||||
|
filterDom = (string: string) => {
|
||||||
|
string = string.replace(
|
||||||
|
/(<a)(.*?>.*)(<\/a>)/g,
|
||||||
|
// @ts-ignore
|
||||||
|
function (string, head, body, tail) {
|
||||||
|
body = body.replace(/href=".*?"(.*>)/, '$1')
|
||||||
|
return `<span${body}</span>`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
string = string.replace(/<script.*?<\/script>/, '')
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
string = string.replace(/(<form .*action=")(.*)/g, function (string, form) {
|
||||||
|
return `${form}#`
|
||||||
|
})
|
||||||
|
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
get template() {
|
||||||
|
return `
|
||||||
|
<div id="gaia-widget-container-${this.createTime}"></div>
|
||||||
|
<style>${this.shadowStyle}</style>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
get shadowStyle() {
|
||||||
|
return `
|
||||||
|
:host {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host > div[id^=gaia-widget-container-] {
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
customElements.define('gaia-widget', GaiaWidget)
|
||||||
|
} catch (error) {}
|
|
@ -21,6 +21,8 @@ export const watchFiles = async () => {
|
||||||
const files = await fg([
|
const files = await fg([
|
||||||
'./src/components/**/!(*.d).ts',
|
'./src/components/**/!(*.d).ts',
|
||||||
'./src/lib/**/!(*.d).ts',
|
'./src/lib/**/!(*.d).ts',
|
||||||
|
"src/widgets/*.ts",
|
||||||
|
"src/widgets/**/*.ts"
|
||||||
])
|
])
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"emitDeclarationOnly": false
|
"emitDeclarationOnly": false
|
||||||
},
|
},
|
||||||
"include": ["src/components/**/*.ts", "src/lib/**/*.ts"],
|
"include": ["src/components/**/*.ts", "src/lib/**/*.ts", "src/widgets/*.ts", "src/widgets/**/.ts"],
|
||||||
"exclude": ["src/*/node_modules/**/*.ts"]
|
"exclude": ["src/*/node_modules/**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {defineConfig} from 'vite'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: `src/widgets/${process.env.WIDGET_FILE_NAME}/${process.env.WIDGET_FILE_NAME}.ts`,
|
||||||
|
formats: ['es'],
|
||||||
|
fileName: `${process.env.WIDGET_FILE_NAME}`
|
||||||
|
},
|
||||||
|
outDir: `dist/widgets/${process.env.WIDGET_FILE_NAME}/`,
|
||||||
|
},
|
||||||
|
})
|
Loading…
Reference in New Issue