Skip to content

Commit 8627db0

Browse files
JayaKrishnaNamburuWilliam Gounot
and
William Gounot
authored
(feat): Support for nested asset-paths (#750)
* (feat): allow assets being referenced in nested paths * Fix tests for asset handling * fixed file injection path + added customizable asset folder path setting * Fix for asset handling and file injection --------- Co-authored-by: William Gounot <[email protected]>
1 parent 35bbfa2 commit 8627db0

File tree

22 files changed

+10345
-10130
lines changed

22 files changed

+10345
-10130
lines changed

examples/uidl-samples/project.json

+10,057-10,005
Large diffs are not rendered by default.

packages/teleport-code-generator/src/index.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,14 @@ const projectPublisherFactories: Omit<Record<PublisherType, Function>, Publisher
111111

112112
export const packProject: PackProjectFunction = async (
113113
projectUIDL,
114-
{ projectType, publisher: publisherType, publishOptions = {}, assets = [], plugins = [] }
114+
{
115+
projectType,
116+
publisher: publisherType,
117+
publishOptions = {},
118+
assets = [],
119+
plugins = [],
120+
assetsFolder = [Constants.ASSETS_IDENTIFIER],
121+
}
115122
) => {
116123
const packer = createProjectPacker()
117124
let publisher
@@ -159,7 +166,7 @@ export const packProject: PackProjectFunction = async (
159166

160167
packer.setAssets({
161168
assets,
162-
path: [Constants.ASSETS_IDENTIFIER],
169+
path: assetsFolder,
163170
})
164171

165172
packer.setGenerator(projectGeneratorFactory)

packages/teleport-component-generator-html/src/index.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
HTMLComponentGenerator,
88
ComponentUIDL,
99
GeneratorFactoryParams,
10+
GeneratorOptions,
1011
} from '@teleporthq/teleport-types'
1112
import { createComponentGenerator } from '@teleporthq/teleport-component-generator'
1213
import { StringUtils } from '@teleporthq/teleport-shared'
@@ -26,15 +27,19 @@ const createHTMLComponentGenerator: HTMLComponentGeneratorInstance = ({
2627
mappings.forEach((mapping) => resolver.addMapping(mapping))
2728

2829
Object.defineProperty(generator, 'addExternalComponents', {
29-
value: (params: { externals: Record<string, ComponentUIDL>; skipValidation?: boolean }) => {
30-
const { externals = {}, skipValidation = false } = params
30+
value: (params: {
31+
externals: Record<string, ComponentUIDL>
32+
skipValidation?: boolean
33+
assets?: GeneratorOptions['assets']
34+
}) => {
35+
const { externals = {}, skipValidation = false, assets = {} } = params
3136
addExternals(
3237
Object.keys(externals).reduce((acc: Record<string, ComponentUIDL>, ext) => {
3338
const componentUIDL = skipValidation
3439
? externals[ext]
3540
: Parser.parseComponentJSON(externals[ext] as unknown as Record<string, unknown>)
3641
const resolvedUIDL = resolver.resolveUIDL(componentUIDL, {
37-
assetsPrefix: 'public',
42+
assets,
3843
})
3944
acc[StringUtils.dashCaseToUpperCamelCase(ext)] = resolvedUIDL
4045
return acc

packages/teleport-plugin-common/src/builders/ast-builders.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ export const appendAssetsAST = (
191191
assets.forEach((asset) => {
192192
let assetPath
193193
if ('path' in asset) {
194-
assetPath = UIDLUtils.prefixAssetsPath(options.assetsPrefix, asset.path)
194+
assetPath = UIDLUtils.prefixAssetsPath(asset.path, options?.assets)
195195
}
196196

197197
// link canonical for SEO

packages/teleport-project-generator-html/__tests__/end2end/index.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ import HTMLTemplate from '../../src/project-template'
66
import { FileType } from '@teleporthq/teleport-types'
77

88
describe('Html Project Generator', () => {
9-
const generator = createHTMLProjectGenerator()
10-
119
it('runs without crasing', async () => {
10+
const generator = createHTMLProjectGenerator()
11+
generator.setAssets({
12+
mappings: {},
13+
identifier: 'playground_assets',
14+
})
1215
const { name, files, subFolders } = await generator.generateProject(uidlSample, HTMLTemplate)
1316
const aboutPage = files.find((page) => page.name === 'about' && page.fileType === FileType.HTML)
1417
const aboutCSS = files.find((page) => page.name === 'about' && page.fileType === FileType.CSS)
@@ -25,6 +28,10 @@ describe('Html Project Generator', () => {
2528

2629
it('run withut crashing and appends entry things into single index.html', async () => {
2730
const singularGenerator = createHTMLProjectGenerator({ individualEntyFile: false })
31+
singularGenerator.setAssets({
32+
mappings: {},
33+
identifier: 'playground_assets',
34+
})
2835
const { name, files, subFolders } = await singularGenerator.generateProject(
2936
uidlSample,
3037
HTMLTemplate
@@ -42,15 +49,19 @@ describe('Html Project Generator', () => {
4249
})
4350

4451
it('throws error when invalid UIDL sample is used', async () => {
52+
const generator = createHTMLProjectGenerator()
4553
const result = generator.generateProject(invalidUidlSample, HTMLTemplate)
4654
await expect(result).rejects.toThrow(Error)
4755
})
4856
})
4957

5058
describe('Unwinds the slot inside the component when used in page', () => {
51-
const generator = createHTMLProjectGenerator()
52-
5359
it('runs without crashing', async () => {
60+
const generator = createHTMLProjectGenerator()
61+
generator.setAssets({
62+
mappings: {},
63+
identifier: 'playground_assets',
64+
})
5465
const result = await generator.generateProject(projectWithSlot, HTMLTemplate)
5566
const indexFile = result.files.find(
5667
(file) => file.name === 'index' && file.fileType === FileType.HTML

packages/teleport-project-generator-html/__tests__/index.ts

+17
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ import uidlWithImages from '../../../examples/test-samples/html-image-use-cases.
99
describe('Passes the rootClass which using the component', () => {
1010
it('run without crashing while using with HTML', async () => {
1111
const generator = createHTMLProjectGenerator()
12+
generator.setAssets({
13+
mappings: {},
14+
identifier: 'playground_assets',
15+
prefix: '/public',
16+
})
1217
const result = await generator.generateProject(uidlWithCompStyleOverrides)
1318

1419
const mainFile = result.files.find(
@@ -27,6 +32,11 @@ describe('Passes the rootClass which using the component', () => {
2732
describe('Image Resolution', () => {
2833
it('resolves all local assets to be refered from public folder', async () => {
2934
const generator = createHTMLProjectGenerator()
35+
generator.setAssets({
36+
mappings: {},
37+
identifier: 'playground_assets',
38+
prefix: '/public',
39+
})
3040
const { files } = await generator.generateProject(uidlWithImages)
3141

3242
const mainCSS = files.find((file) => file.name === 'home' && file.fileType === FileType.CSS)
@@ -60,7 +70,14 @@ describe('Image Resolution', () => {
6070

6171
it('creates a default route if a page is marked as fallback', async () => {
6272
const generator = createHTMLProjectGenerator()
73+
74+
generator.setAssets({
75+
mappings: {},
76+
identifier: 'playground_assets',
77+
prefix: '/public',
78+
})
6379
generator.addPlugin(htmlErrorPageMapping)
80+
6481
const { files } = await generator.generateProject(fallbackUidlSample, ProjectTemplate)
6582
const fallbackPage = files.find((file) => file.name === '404')
6683

packages/teleport-project-generator-next/src/utils.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,18 @@ export const createDocumentFileChunks = (uidl: ProjectUIDL, options: EntryFileOp
3434
if (manifest) {
3535
const linkTag = ASTBuilders.createJSXTag('link')
3636
ASTUtils.addAttributeToJSXTag(linkTag, 'rel', 'manifest')
37-
ASTUtils.addAttributeToJSXTag(linkTag, 'href', `${options.assetsPrefix}/manifest.json`)
37+
ASTUtils.addAttributeToJSXTag(
38+
linkTag,
39+
'href',
40+
UIDLUtils.prefixAssetsPath(`/manifest.json`, options.assets)
41+
)
3842
ASTUtils.addChildJSXTag(headNode, linkTag)
3943
}
4044

4145
meta.forEach((metaItem) => {
4246
const metaTag = ASTBuilders.createJSXTag('meta')
4347
Object.keys(metaItem).forEach((key) => {
44-
const metaValue = UIDLUtils.prefixAssetsPath(options.assetsPrefix, metaItem[key])
48+
const metaValue = UIDLUtils.prefixAssetsPath(metaItem[key], options.assets)
4549
ASTUtils.addAttributeToJSXTag(metaTag, key, metaValue)
4650
})
4751
ASTUtils.addChildJSXTag(headNode, metaTag)

packages/teleport-project-generator/__tests__/file-handlers.ts

+20-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { handlePackageJSON, createEntryFile, createManifestJSONFile } from '../src/file-handlers'
22
import { PackageJSON } from '../src/types'
3-
import { GeneratedFolder, ProjectUIDL, FileType } from '@teleporthq/teleport-types'
3+
import {
4+
GeneratedFolder,
5+
ProjectUIDL,
6+
FileType,
7+
UIDLRootComponent,
8+
} from '@teleporthq/teleport-types'
49
import { component, elementNode } from '@teleporthq/teleport-uidl-builders'
510
import { createStrategyWithCommonGenerator } from './mocks'
611

@@ -9,7 +14,11 @@ import uidlSample from '../../../examples/test-samples/project-sample.json'
914
describe('createHtmlIndexFile', () => {
1015
it('returns index file with prefixed assets and app file', async () => {
1116
const options = {
12-
assetsPrefix: '/static',
17+
assets: {
18+
prefix: '',
19+
mappings: {},
20+
identifier: 'playground_assets',
21+
},
1322
appRootOverride: '{{root-placeholder}}',
1423
}
1524
const [entryFile] = await createEntryFile(
@@ -25,16 +34,21 @@ describe('createHtmlIndexFile', () => {
2534

2635
describe('createManifestJSONFile', () => {
2736
it('returns manifest file with prefixed assets', () => {
28-
const assetsPrefix = 'playground'
29-
const result = createManifestJSONFile(uidlSample as unknown as ProjectUIDL, assetsPrefix)
37+
const result = createManifestJSONFile(uidlSample as unknown as ProjectUIDL, {
38+
prefix: 'playground',
39+
identifier: 'playground_assets',
40+
mappings: { 'icons-192.png': '' },
41+
})
3042

3143
expect(result.name).toBe('manifest')
3244
expect(result.fileType).toBe('json')
3345
expect(result.content).toContain('"src": "playground/playground_assets/')
3446
})
3547

3648
it('returns manifest file with no prefixed assets', () => {
37-
const result = createManifestJSONFile(uidlSample as unknown as ProjectUIDL)
49+
const result = createManifestJSONFile(uidlSample as unknown as ProjectUIDL, {
50+
identifier: 'playground_assets',
51+
})
3852

3953
expect(result.name).toBe('manifest')
4054
expect(result.fileType).toBe('json')
@@ -46,7 +60,7 @@ describe('handlePackageJSON', () => {
4660
const uidl: ProjectUIDL = {
4761
name: 'test-project',
4862
globals: { settings: { title: 'Random', language: 'en' }, meta: [], assets: [] },
49-
root: component('random', elementNode('container')),
63+
root: component('random', elementNode('container')) as UIDLRootComponent,
5064
}
5165

5266
const dependencies = {

packages/teleport-project-generator/__tests__/index.ts

+24-4
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ describe('Generic Project Generator', () => {
4747
expect(generator.componentGenerator.generateComponent).toBeCalledWith(
4848
expect.objectContaining({ name: 'ExpandableArea' }),
4949
expect.objectContaining({
50-
assetsPrefix: '/test/static',
50+
assets: {
51+
identifier: null,
52+
mappings: {},
53+
prefix: '/test/static',
54+
},
55+
designLanguage: undefined,
5156
mapping: {},
5257
skipValidation: true,
5358
})
@@ -105,7 +110,12 @@ describe('Generic Project Generator', () => {
105110
expect(generator.componentGenerator.generateComponent).toBeCalledWith(
106111
expect.objectContaining({ name: 'ExpandableArea' }),
107112
{
108-
assetsPrefix: '/static',
113+
assets: {
114+
identifier: null,
115+
mappings: {},
116+
prefix: '/static',
117+
},
118+
designLanguage: undefined,
109119
projectRouteDefinition: uidl.root.stateDefinitions.route,
110120
mapping: {},
111121
skipValidation: true,
@@ -117,7 +127,12 @@ describe('Generic Project Generator', () => {
117127
name: 'Home',
118128
}),
119129
{
120-
assetsPrefix: '/static',
130+
assets: {
131+
identifier: null,
132+
mappings: {},
133+
prefix: '/static',
134+
},
135+
designLanguage: undefined,
121136
projectRouteDefinition: uidl.root.stateDefinitions.route,
122137
mapping: {},
123138
skipValidation: true,
@@ -164,7 +179,12 @@ describe('Generic Project Generator', () => {
164179
expect(generator.componentGenerator.generateComponent).toBeCalledWith(
165180
expect.objectContaining({ name: 'ExpandableArea' }),
166181
{
167-
assetsPrefix: '/test/static',
182+
assets: {
183+
identifier: null,
184+
mappings: {},
185+
prefix: '/test/static',
186+
},
187+
designLanguage: undefined,
168188
projectRouteDefinition: uidl.root.stateDefinitions.route,
169189
mapping: {},
170190
skipValidation: true,

packages/teleport-project-generator/src/file-handlers.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export const createEntryFile = async (
123123
// If no function is provided in the strategy, the createHTMLEntryFileChunks is used by default
124124
const chunkGenerationFunction =
125125
strategy.entry?.chunkGenerationFunction || createHTMLEntryFileChunks
126-
const { assetsPrefix } = entryFileOptions
126+
const { assets } = entryFileOptions
127127
const options = { ...strategy.entry?.options, ...entryFileOptions }
128128

129129
const appRootOverride = (options && options.appRootOverride) || null
@@ -132,7 +132,7 @@ export const createEntryFile = async (
132132
const customHeadContent = (options && options.customHeadContent) || null
133133
const customTags = (options && options.customTags) || []
134134
const chunks = chunkGenerationFunction(uidl, {
135-
assetsPrefix,
135+
assets,
136136
appRootOverride,
137137
customHeadContent,
138138
customTags,
@@ -147,7 +147,7 @@ const createHTMLEntryFileChunks = (
147147
uidl: ProjectUIDL,
148148
options: EntryFileOptions
149149
): Record<string, ChunkDefinition[]> => {
150-
const { assetsPrefix = '', appRootOverride, customHeadContent, customTags } = options
150+
const { appRootOverride, customHeadContent, customTags } = options
151151
const { settings, meta, assets, manifest, customCode } = uidl.globals
152152

153153
const htmlNode = HASTBuilders.createHTMLNode('html')
@@ -207,14 +207,18 @@ const createHTMLEntryFileChunks = (
207207
if (manifest) {
208208
const linkTag = HASTBuilders.createHTMLNode('link')
209209
HASTUtils.addAttributeToNode(linkTag, 'rel', 'manifest')
210-
HASTUtils.addAttributeToNode(linkTag, 'href', `${options.assetsPrefix}/manifest.json`)
210+
HASTUtils.addAttributeToNode(
211+
linkTag,
212+
'href',
213+
UIDLUtils.prefixAssetsPath('/manifest.json', options.assets)
214+
)
211215
HASTUtils.addChildNode(headNode, linkTag)
212216
}
213217

214218
meta.forEach((metaItem) => {
215219
const metaTag = HASTBuilders.createHTMLNode('meta')
216220
Object.keys(metaItem).forEach((key) => {
217-
const prefixedURL = UIDLUtils.prefixAssetsPath(assetsPrefix, metaItem[key])
221+
const prefixedURL = UIDLUtils.prefixAssetsPath(metaItem[key], options.assets)
218222
HASTUtils.addAttributeToNode(metaTag, key, prefixedURL)
219223
})
220224
HASTUtils.addChildNode(headNode, metaTag)
@@ -223,7 +227,7 @@ const createHTMLEntryFileChunks = (
223227
assets.forEach((asset) => {
224228
let assetPath
225229
if ('path' in asset) {
226-
assetPath = UIDLUtils.prefixAssetsPath(options.assetsPrefix, asset.path)
230+
assetPath = UIDLUtils.prefixAssetsPath(asset.path, options.assets)
227231
}
228232

229233
// link canonical for SEO
@@ -347,7 +351,10 @@ const createHTMLEntryFileChunks = (
347351
}
348352

349353
// Creates a manifest json file with the UIDL having priority over the default values
350-
export const createManifestJSONFile = (uidl: ProjectUIDL, assetsPrefix?: string): GeneratedFile => {
354+
export const createManifestJSONFile = (
355+
uidl: ProjectUIDL,
356+
assets: GeneratorOptions['assets']
357+
): GeneratedFile => {
351358
const manifest = uidl.globals.manifest
352359
const projectName = uidl.name
353360
const defaultManifest: WebManifest = {
@@ -358,7 +365,7 @@ export const createManifestJSONFile = (uidl: ProjectUIDL, assetsPrefix?: string)
358365
}
359366

360367
const icons = manifest.icons.map((icon) => {
361-
const src = UIDLUtils.prefixAssetsPath(assetsPrefix || '', icon.src)
368+
const src = UIDLUtils.prefixAssetsPath(icon.src, assets)
362369
return { ...icon, src }
363370
})
364371

0 commit comments

Comments
 (0)