Skip to content

Instantly share code, notes, and snippets.

@shikaan
Last active May 4, 2021 13:21
Show Gist options
  • Save shikaan/f1aa1b9cea565352729e85ac7e2635ca to your computer and use it in GitHub Desktop.
Save shikaan/f1aa1b9cea565352729e85ac7e2635ca to your computer and use it in GitHub Desktop.
Contentful UI Extension -> App
CONTENTFUL_MANAGEMENT_TOKEN=
CONTENTFUL_EXTENSION_ID=
CONTENTFUL_ORGANIZATION_ID=
CONTENTFUL_SPACE_ID=
CONTENTFUL_ENVIRONMENT_ID=

Contentful UI Extension -> App

Usage

  1. Run npm i
  2. Fill .env
  3. Run npm start

Limitations

  • works only for srcDocs extensions
  • appizeSrcDocs covers only a very simple case, this should be expanded to take more things in account
  • only caters for field level extensions
const dotenv = require('dotenv');
const { upload } = require('@contentful/app-scripts');
const { createClient } = require('contentful-management')
const fs = require('fs')
const path = require('path')
const mkdirp = require('mkdirp')
const chalk = require('chalk')
const HTMLParser = require('node-html-parser')
const log = {
debug: (message, ...args) => console.log(`${chalk.bgGray.black(' debug ')} ${message}`, ...args.map(i => chalk.gray.underline(i))),
info: (message, ...args) => console.log(`${chalk.bgBlue.black(' info ')} ${message}`, ...args.map(i => chalk.blueBright.underline(i))),
error: (message, ...args) => console.log(`${chalk.bgRed.black(' error ')} ${message}`, ...args.map(i => chalk.redBright.underline(i))),
success: (message, ...args) => console.log(`${chalk.bgGreen.black(' success ')} ${message}`, ...args.map(i => chalk.greenBright.underline(i)))
}
const requiredEnvVar = (environment, variable) => {
if (!environment[variable]) {
log.error('Variable %s is required. Add it to your environment or to the .env file.', variable)
process.exit(1)
}
return environment[variable]
}
const getConfig = () => {
dotenv.config()
return {
accessToken: requiredEnvVar(process.env, 'CONTENTFUL_MANAGEMENT_TOKEN'),
spaceId: requiredEnvVar(process.env, 'CONTENTFUL_SPACE_ID'),
environmentId: requiredEnvVar(process.env, 'CONTENTFUL_ENVIRONMENT_ID'),
extensionId: requiredEnvVar(process.env, 'CONTENTFUL_EXTENSION_ID'),
organizationId: requiredEnvVar(process.env, 'CONTENTFUL_ORGANIZATION_ID'),
buildUrl: path.join(__dirname, './build')
}
}
/**
* Takes an extension body and converts (best effort) to an app body
*
* @param {string} srcDoc
*/
const appizeSrcDocs = (srcDoc) => {
const tree = HTMLParser.parse(srcDoc)
const uieSDKScriptNode = tree
.querySelectorAll('script')
.find(i => /contentful-ui-extensions-sdk/.test(i.getAttribute('src')))
uieSDKScriptNode.setAttribute('src', 'https://unpkg.com/@contentful/app-sdk@3')
return tree.toString().replace('window.contentfulExtension.init', 'window.contentfulApp.init')
}
;(async function main () {
console.log(`
This script will convert an existing Contentful-Hosted UI Extension
to a Contentful-Hosted App.
`)
const {accessToken, spaceId, environmentId, extensionId, buildUrl, organizationId } = getConfig();
log.info('Utilizing space %s, environment %s', spaceId, environmentId);
const client = createClient({ accessToken }, { type: 'plain',
defaults: {
spaceId,
environmentId,
organizationId,
}
})
log.info('Getting extension with id %s', extensionId);
const {extension} = await client.extension.get({ extensionId });
if (!extension.srcdoc) {
log.error('Extension %s does not have a %s attribute', extensionId, 'srcdoc')
process.exit(1);
}
log.success('Got extension %s', extension.name);
log.info('Converting extension to app in %s', buildUrl)
const index = appizeSrcDocs(extension.srcdoc)
mkdirp.sync(buildUrl);
fs.writeFileSync(path.join(buildUrl, 'index.html'), index);
log.success('Successfully converted app')
log.info('Creating an app definition for extension %s', extension.name)
const definition = await client.appDefinition.create({organizationId}, {
name: extension.name,
src: 'http://localhost:3000',
locations: [
{
location: 'entry-field',
fieldTypes: extension.fieldTypes
}
],
parameters: extension.parameters
})
log.success('Created app %s', definition.sys.id)
log.info('Hosting your app in Contentful')
await upload.nonInteractive({
organizationId,
definitionId: definition.sys.id,
token: accessToken,
bundleDir: buildUrl,
comment: 'Autogenerated',
skipActivation: false,
})
log.success('Your %s extension is now a Contentful-hosted App! 🎉', extension.name)
})();
{
"name": "uie-to-hosted-app",
"version": "0.0.1",
"main": "main.js",
"scripts": {
"start": "node ."
},
"author": "Manuel Spagnolo <manuel.spagnolo@mail.com>",
"dependencies": {
"@contentful/app-scripts": "^0.7.0",
"chalk": "^4.1.0",
"contentful-management": "^7.15.1",
"dotenv": "^8.2.0",
"mkdirp": "^1.0.4",
"node-html-parser": "^3.1.5"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment