inject.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. const fs = require('fs')
  2. const path = require('path')
  3. const chalk = require('chalk')
  4. const { exec } = require('child_process')
  5. const YAML = require('js-yaml')
  6. const { promisify } = require('util')
  7. const gzipSize = require('gzip-size')
  8. const bytes = require('pretty-bytes')
  9. const browserify = require('browserify')
  10. const touch = require('touch')
  11. const glob = require('glob')
  12. const LocaleCode = require('locale-code')
  13. const webRoot = __dirname
  14. const uppyRoot = path.join(__dirname, '../packages/uppy')
  15. const robodogRoot = path.join(__dirname, '../packages/@uppy/robodog')
  16. const localesRoot = path.join(__dirname, '../packages/@uppy/locales')
  17. const configPath = path.join(webRoot, '/themes/uppy/_config.yml')
  18. const { version } = require(path.join(uppyRoot, '/package.json'))
  19. const defaultConfig = {
  20. comment: 'Auto updated by inject.js',
  21. uppy_version_anchor: '001',
  22. uppy_version: '0.0.1',
  23. uppy_bundle_kb_sizes: {},
  24. config: {}
  25. }
  26. // Keeping a whitelist so utils etc are excluded
  27. // It may be easier to maintain a blacklist instead
  28. const packages = [
  29. 'uppy',
  30. '@uppy/core',
  31. '@uppy/dashboard',
  32. '@uppy/drag-drop',
  33. '@uppy/file-input',
  34. '@uppy/webcam',
  35. '@uppy/screen-capture',
  36. '@uppy/dropbox',
  37. '@uppy/google-drive',
  38. '@uppy/instagram',
  39. '@uppy/url',
  40. '@uppy/tus',
  41. '@uppy/xhr-upload',
  42. '@uppy/aws-s3',
  43. '@uppy/aws-s3-multipart',
  44. '@uppy/status-bar',
  45. '@uppy/progress-bar',
  46. '@uppy/informer',
  47. '@uppy/transloadit',
  48. '@uppy/form',
  49. '@uppy/golden-retriever',
  50. '@uppy/react',
  51. '@uppy/thumbnail-generator',
  52. '@uppy/store-default',
  53. '@uppy/store-redux'
  54. ]
  55. const excludes = {
  56. '@uppy/react': ['react']
  57. }
  58. inject().catch((err) => {
  59. console.error(err)
  60. process.exit(1)
  61. })
  62. async function getMinifiedSize (pkg, name) {
  63. const b = browserify(pkg)
  64. const packageJSON = fs.readFileSync(path.join(pkg, 'package.json'))
  65. const version = JSON.parse(packageJSON).version
  66. if (name !== '@uppy/core' && name !== 'uppy') {
  67. b.exclude('@uppy/core')
  68. // Already unconditionally included through @uppy/core
  69. b.exclude('preact')
  70. }
  71. if (excludes[name]) {
  72. b.exclude(excludes[name])
  73. }
  74. b.plugin('tinyify')
  75. const bundle = await promisify(b.bundle).call(b)
  76. const gzipped = await gzipSize(bundle)
  77. return {
  78. minified: bundle.length,
  79. gzipped,
  80. version
  81. }
  82. }
  83. async function injectSizes (config) {
  84. console.info(chalk.grey('Generating bundle sizes…'))
  85. const padTarget = packages.reduce((max, cur) => Math.max(max, cur.length), 0) + 2
  86. const sizesPromise = Promise.all(
  87. packages.map(async (pkg) => {
  88. const result = await getMinifiedSize(path.join(__dirname, '../packages', pkg), pkg)
  89. console.info(chalk.green(
  90. // ✓ @uppy/pkgname: 10.0 kB min / 2.0 kB gz
  91. ` ✓ ${pkg}: ${' '.repeat(padTarget - pkg.length)}` +
  92. `${bytes(result.minified)} min`.padEnd(10) +
  93. ` / ${bytes(result.gzipped)} gz`
  94. ))
  95. return Object.assign(result, {
  96. prettyMinified: bytes(result.minified),
  97. prettyGzipped: bytes(result.gzipped)
  98. })
  99. })
  100. ).then((list) => {
  101. const map = {}
  102. list.forEach((size, i) => {
  103. map[packages[i]] = size
  104. })
  105. return map
  106. })
  107. config.uppy_bundle_kb_sizes = await sizesPromise
  108. }
  109. async function injectBundles () {
  110. const cmds = [
  111. `mkdir -p ${path.join(webRoot, '/themes/uppy/source/uppy')}`,
  112. `mkdir -p ${path.join(webRoot, '/themes/uppy/source/uppy/locales')}`,
  113. `cp -vfR ${path.join(uppyRoot, '/dist/*')} ${path.join(webRoot, '/themes/uppy/source/uppy/')}`,
  114. `cp -vfR ${path.join(robodogRoot, '/dist/*')} ${path.join(webRoot, '/themes/uppy/source/uppy/')}`,
  115. `cp -vfR ${path.join(localesRoot, '/dist/*')} ${path.join(webRoot, '/themes/uppy/source/uppy/locales')}`
  116. ].join(' && ')
  117. const { stdout } = await promisify(exec)(cmds)
  118. stdout.trim().split('\n').forEach(function (line) {
  119. console.info(chalk.green('✓ injected: '), chalk.grey(line))
  120. })
  121. }
  122. // re-enable after rate limiter issue is fixed
  123. //
  124. async function injectGhStars () {
  125. const opts = {}
  126. if ('GITHUB_TOKEN' in process.env) {
  127. opts.auth = process.env.GITHUB_TOKEN
  128. }
  129. const { Octokit } = require('@octokit/rest')
  130. const octokit = new Octokit(opts)
  131. const { headers, data } = await octokit.repos.get({
  132. owner: 'transloadit',
  133. repo: 'uppy'
  134. })
  135. console.log(`${headers['x-ratelimit-remaining']} requests remaining until we hit GitHub ratelimiter`)
  136. const dstpath = path.join(webRoot, 'themes', 'uppy', 'layout', 'partials', 'generated_stargazers.ejs')
  137. fs.writeFileSync(dstpath, data.stargazers_count, 'utf-8')
  138. console.log(`${data.stargazers_count} stargazers written to '${dstpath}'`)
  139. }
  140. async function injectMarkdown () {
  141. const sources = {
  142. '.github/ISSUE_TEMPLATE/integration_help.md': 'src/_template/integration_help.md',
  143. '.github/CONTRIBUTING.md': 'src/_template/contributing.md'
  144. }
  145. for (const src in sources) {
  146. const dst = sources[src]
  147. // strip yaml frontmatter:
  148. const srcpath = path.join(uppyRoot, `/../../${src}`)
  149. const dstpath = path.join(webRoot, dst)
  150. const parts = fs.readFileSync(srcpath, 'utf-8').split(/---\s*\n/)
  151. if (parts.length >= 3) {
  152. parts.shift()
  153. parts.shift()
  154. }
  155. let content = `<!-- WARNING! This file was injected. Please edit in "${src}" instead and run "${path.basename(__filename)}" -->\n\n`
  156. content += parts.join('---\n')
  157. fs.writeFileSync(dstpath, content, 'utf-8')
  158. console.info(chalk.green('✓ injected: '), chalk.grey(srcpath))
  159. }
  160. touch(path.join(webRoot, '/src/support.md'))
  161. }
  162. function injectLocaleList () {
  163. const mdTable = [
  164. `<!-- WARNING! This file was automatically injected. Please run "${path.basename(__filename)}" to re-generate -->\n\n`,
  165. '| %count% Locales | NPM | CDN | Source on GitHub |',
  166. '| --------------- | ------------------ | ------------------- | ---------------- |'
  167. ]
  168. const mdRows = []
  169. const localeList = {}
  170. const localePackagePath = path.join(localesRoot, 'src', '*.js')
  171. const localePackageVersion = require(path.join(localesRoot, 'package.json')).version
  172. glob.sync(localePackagePath).forEach((localePath) => {
  173. const localeName = path.basename(localePath, '.js')
  174. // we renamed the es_GL → gl_ES locale, and kept the old name
  175. // for backwards-compat, see https://github.com/transloadit/uppy/pull/1929
  176. if (localeName === 'es_GL') return
  177. let localeNameWithDash = localeName.replace(/_/g, '-')
  178. const parts = localeNameWithDash.split('-')
  179. let variant = ''
  180. if (parts.length > 2) {
  181. const lang = parts.shift()
  182. const country = parts.shift()
  183. variant = parts.join(', ')
  184. localeNameWithDash = `${lang}-${country}`
  185. }
  186. const languageName = LocaleCode.getLanguageName(localeNameWithDash)
  187. const countryName = LocaleCode.getCountryName(localeNameWithDash)
  188. const npmPath = `<code class="raw"><a href="https://www.npmjs.com/package/@uppy/locales">@uppy/locales</a>/lib/${localeName}</code>`
  189. const cdnPath = `[\`${localeName}.min.js\`](https://transloadit.edgly.net/releases/uppy/locales/v${localePackageVersion}/${localeName}.min.js)`
  190. const githubSource = `[\`${localeName}.js\`](https://github.com/transloadit/uppy/blob/master/packages/%40uppy/locales/src/${localeName}.js)`
  191. const mdTableRow = `| ${languageName}<br/> <small>${countryName}</small>${variant ? `<br /><small>(${variant})</small>` : ''} | ${npmPath} | ${cdnPath} | ✏️ ${githubSource} |`
  192. mdRows.push(mdTableRow)
  193. localeList[localeName] = `${languageName} (${countryName}${variant ? ` ${variant}` : ''})`
  194. })
  195. const resultingMdTable = mdTable.concat(mdRows.sort()).join('\n').replace('%count%', mdRows.length)
  196. const dstpath = path.join(webRoot, 'src', '_template', 'list_of_locale_packs.md')
  197. const localeListDstPath = path.join(webRoot, 'src', 'examples', 'locale_list.json')
  198. fs.writeFileSync(dstpath, resultingMdTable, 'utf-8')
  199. console.info(chalk.green('✓ injected: '), chalk.grey(dstpath))
  200. fs.writeFileSync(localeListDstPath, JSON.stringify(localeList), 'utf-8')
  201. console.info(chalk.green('✓ injected: '), chalk.grey(localeListDstPath))
  202. }
  203. async function readConfig () {
  204. try {
  205. const buf = await promisify(fs.readFile)(configPath, 'utf8')
  206. return YAML.safeLoad(buf)
  207. } catch (err) {
  208. return {}
  209. }
  210. }
  211. async function inject () {
  212. const config = await readConfig()
  213. await injectGhStars()
  214. await injectMarkdown()
  215. injectLocaleList()
  216. config.uppy_version = version
  217. config.uppy_version_anchor = version.replace(/[^\d]+/g, '')
  218. await injectSizes(config)
  219. const saveConfig = Object.assign({}, defaultConfig, config)
  220. await promisify(fs.writeFile)(configPath, YAML.safeDump(saveConfig), 'utf-8')
  221. console.info(chalk.green('✓ rewritten: '), chalk.grey(configPath))
  222. try {
  223. await injectBundles()
  224. } catch (error) {
  225. console.error(
  226. chalk.red('x failed to inject: '),
  227. chalk.grey('uppy bundle into site, because: ' + error)
  228. )
  229. process.exit(1)
  230. }
  231. }