rollup.config.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. const path = require('path')
  2. const { readFileSync } = require('fs')
  3. const glob = require('glob')
  4. const nodeResolve = require('rollup-plugin-node-resolve')
  5. const commonjs = require('rollup-plugin-commonjs')
  6. const multiEntry = require('rollup-plugin-multi-entry')
  7. const sourcemaps = require('rollup-plugin-sourcemaps')
  8. const alias = require('rollup-plugin-alias')
  9. const replace = require('rollup-plugin-replace')
  10. const cleanup = require('rollup-plugin-cleanup')
  11. const handleBars = require('handlebars')
  12. const { pkgStructs } = require('./scripts/lib/pkg-struct')
  13. const rootPkgJsonData = require('./package.json')
  14. const EXTERNAL_BROWSER_GLOBALS = {
  15. luxon: 'luxon',
  16. rrule: 'rrule',
  17. moment: 'moment'
  18. }
  19. const EXTERNAL_BROWSER_GLOBAL_HACKS = {
  20. 'moment-timezone/builds/moment-timezone-with-data': 'moment' // see moment-timezone/src/main.ts
  21. }
  22. const WATCH_OPTIONS = {
  23. chokidar: { // better than default watch util. doesn't fire change events on stat changes (like last opened)
  24. awaitWriteFinish: { // because tsc/rollup sometimes takes a long time to write and triggers two recompiles
  25. stabilityThreshold: 500,
  26. pollInterval: 100
  27. }
  28. },
  29. clearScreen: false // let tsc do the screan clearing
  30. }
  31. const renderBanner = handleBars.compile(
  32. readFileSync('packages/banner.tpl', { encoding: 'utf8' })
  33. )
  34. module.exports = buildConfigs()
  35. function buildConfigs() {
  36. let isDev = detectIsDev()
  37. let ownBrowserGlobals = {}
  38. for (let pkgStruct of pkgStructs) {
  39. ownBrowserGlobals[pkgStruct.name] = pkgStruct.browserGlobal
  40. }
  41. return [
  42. ...buildPkgConfigs(ownBrowserGlobals, isDev),
  43. ...buildLocaleConfigs(ownBrowserGlobals),
  44. buildTestConfig() // must be last b/c depends on built pkgs+locales
  45. ]
  46. }
  47. // FullCalendar Packages
  48. // ----------------------------------------------------------------------------------------------------
  49. function buildPkgConfigs(ownBrowserGlobals, isDev) {
  50. return pkgStructs.map((pkgStruct) => buildPkgConfig(pkgStruct, ownBrowserGlobals, isDev))
  51. }
  52. function buildPkgConfig(pkgStruct, ownBrowserGlobals, isDev) {
  53. let banner = renderBanner(pkgStruct.jsonObj)
  54. let external = Object.keys(Object.assign(
  55. {},
  56. EXTERNAL_BROWSER_GLOBAL_HACKS, // apply to all because didn't have per-pkg data from package.json's
  57. ownBrowserGlobals,
  58. pkgStruct.jsonObj.dependencies || {},
  59. pkgStruct.jsonObj.peerDependencies || {}
  60. ))
  61. let plugins = [
  62. nodeResolve({
  63. only: [ 'tslib' ] // the only external module we want to bundle
  64. }),
  65. replace({
  66. delimiters: [ '<%= ', ' %>' ],
  67. values: {
  68. version: rootPkgJsonData.version,
  69. releaseDate: new Date().toISOString().replace(/T.*/, '')
  70. // ^TODO: store this in package.json for easier old-release recreation
  71. }
  72. })
  73. ]
  74. if (isDev) {
  75. plugins.push(sourcemaps())
  76. // HACK: there's a bug with sourcemap reading and watching: the first rebuild includes the intermediate
  77. // sourceMappingURL comments, confusing consumers of the generated sourcemap. Forcefully remove these comments.
  78. plugins.push(cleanup({ comments: 'none' }))
  79. }
  80. return {
  81. onwarn,
  82. watch: WATCH_OPTIONS,
  83. input: path.join('tmp/tsc-output', pkgStruct.srcDir, 'main.js'),
  84. external,
  85. output: [
  86. {
  87. file: path.join(pkgStruct.distDir, 'main.js'),
  88. format: 'umd',
  89. name: pkgStruct.browserGlobal,
  90. globals: {
  91. ...ownBrowserGlobals,
  92. ...EXTERNAL_BROWSER_GLOBALS,
  93. ...EXTERNAL_BROWSER_GLOBAL_HACKS
  94. },
  95. exports: 'named',
  96. sourcemap: isDev,
  97. banner
  98. },
  99. {
  100. file: path.join(pkgStruct.distDir, 'main.esm.js'),
  101. format: 'esm',
  102. sourcemap: isDev,
  103. banner
  104. }
  105. ],
  106. plugins
  107. }
  108. }
  109. // Locales
  110. // ----------------------------------------------------------------------------------------------------
  111. function buildLocaleConfigs(ownBrowserGlobals) {
  112. let corePkgStruct = getCorePkgStruct()
  113. let coreTmpDir = path.join('tmp/tsc-output', corePkgStruct.srcDir)
  114. let localePaths = glob.sync('locales/*.js', { cwd: coreTmpDir })
  115. let external = Object.keys(ownBrowserGlobals)
  116. let configs = []
  117. for (let localePath of localePaths) {
  118. let localeName = path.basename(localePath).replace(/\..*$/, '')
  119. configs.push({
  120. onwarn,
  121. watch: WATCH_OPTIONS,
  122. input: path.join(coreTmpDir, localePath),
  123. external,
  124. output: {
  125. file: path.join(corePkgStruct.distDir, localePath),
  126. globals: ownBrowserGlobals,
  127. name: 'FullCalendarLocales.' + localeName,
  128. format: 'umd'
  129. }
  130. })
  131. }
  132. // ALL locales in one file
  133. configs.push({
  134. onwarn,
  135. watch: WATCH_OPTIONS,
  136. input: localePaths.map(localePath => path.join(coreTmpDir, localePath)),
  137. external,
  138. output: {
  139. file: path.join(corePkgStruct.distDir, 'locales-all.js'),
  140. globals: ownBrowserGlobals,
  141. name: 'FullCalendarLocalesAll',
  142. format: 'umd'
  143. },
  144. plugins: [
  145. multiEntry({ exports: 'array' })
  146. ]
  147. })
  148. return configs
  149. }
  150. // Tests
  151. // ----------------------------------------------------------------------------------------------------
  152. function buildTestConfig() {
  153. let plugins = [
  154. multiEntry({
  155. exports: false // don't combine all the exports. no need, and would collide
  156. }),
  157. nodeResolve({
  158. customResolveOptions: {
  159. // tests can access all the dependencies they declared. these deps will be bundled.
  160. // apparently this setting is inefficient.
  161. // IMPORTANT: our internal package.jsons need to be written first
  162. paths: [
  163. 'packages/__tests__/node_modules',
  164. 'packages-premium/__tests__/node_modules'
  165. ]
  166. }
  167. }),
  168. alias({
  169. // the alias to the non-premium tests. must be absolute
  170. 'package-tests': path.join(process.cwd(), 'tmp/tsc-output/packages/__tests__/src')
  171. }),
  172. commonjs(), // for fast-deep-equal import
  173. sourcemaps()
  174. ]
  175. return {
  176. onwarn,
  177. watch: WATCH_OPTIONS,
  178. input: [
  179. 'tmp/tsc-output/packages?(-premium)/__tests__/src/globals.js',
  180. 'tmp/tsc-output/packages?(-premium)/__tests__/src/**/*.js'
  181. ],
  182. external: [
  183. // HACK: because hoisting is no yet implemented for the monorepo-tool, when we require our packages,
  184. // *their* dependencies are not deduped, we we get multiple instances of the below libraries in the bundle.
  185. // Until hoisting is implemented, make these external and include them manually from karma.config.js.
  186. 'luxon',
  187. 'rrule',
  188. 'moment',
  189. 'moment/locale/es',
  190. 'moment-timezone/builds/moment-timezone-with-data'
  191. ],
  192. output: {
  193. file: 'tmp/tests.js',
  194. globals: Object.assign({}, EXTERNAL_BROWSER_GLOBALS, EXTERNAL_BROWSER_GLOBAL_HACKS), // HACK (continued)
  195. format: 'iife',
  196. sourcemap: true
  197. },
  198. plugins
  199. }
  200. }
  201. // Utils
  202. // ----------------------------------------------------------------------------------------------------
  203. function getCorePkgStruct() {
  204. for (let pkgStruct of pkgStructs) {
  205. if (pkgStruct.name === '@fullcalendar/core') {
  206. return pkgStruct
  207. }
  208. }
  209. throw new Error('No core package')
  210. }
  211. function onwarn(warning, warn) {
  212. // ignore circ dep warnings. too numerous and hard to fix right now
  213. if (warning.code !== 'CIRCULAR_DEPENDENCY') {
  214. warn(warning)
  215. }
  216. }
  217. function detectIsDev() {
  218. if (!/^(development|production)$/.test(process.env.BUILD)) {
  219. console.warn('BUILD environment not specified. Assuming \'development\'')
  220. return true
  221. } else {
  222. return process.env.BUILD === 'development'
  223. }
  224. }