You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /**
  2. @author : Caven Chen
  3. **/
  4. 'use strict'
  5. import fse from 'fs-extra'
  6. import path from 'path'
  7. import gulp from 'gulp'
  8. import esbuild from 'esbuild'
  9. import concat from 'gulp-concat'
  10. import { rollup } from 'rollup'
  11. import clean from 'gulp-clean'
  12. import commonjs from '@rollup/plugin-commonjs'
  13. import resolve from '@rollup/plugin-node-resolve'
  14. import terser from '@rollup/plugin-terser'
  15. import scss from 'rollup-plugin-scss'
  16. import javascriptObfuscator from 'gulp-javascript-obfuscator'
  17. import { babel } from '@rollup/plugin-babel'
  18. import startServer from './server.js'
  19. import inlineImage from 'esbuild-plugin-inline-image'
  20. import { glsl } from 'esbuild-plugin-glsl'
  21. import chokidar from 'chokidar'
  22. import shell from 'shelljs'
  23. import chalk from 'chalk'
  24. const obfuscatorConfig = {
  25. compact: true, //压缩代码
  26. identifierNamesGenerator: 'hexadecimal', //标识符的混淆方式 hexadecimal(十六进制) mangled(短标识符)
  27. renameGlobals: false, //是否启用全局变量和函数名称的混淆
  28. rotateStringArray: true, //通过固定和随机(在代码混淆时生成)的位置移动数组。这使得将删除的字符串的顺序与其原始位置相匹配变得更加困难。如果原始源代码不小,建议使用此选项,因为辅助函数可以引起注意。
  29. selfDefending: true, //混淆后的代码,不能使用代码美化,同时需要配置 compact:true;
  30. stringArray: true, //删除字符串文字并将它们放在一个特殊的数组中
  31. stringArrayEncoding: ['base64'],
  32. stringArrayThreshold: 0.75,
  33. transformObjectKeys: false,
  34. unicodeEscapeSequence: false, //允许启用/禁用字符串转换为unicode转义序列。Unicode转义序列大大增加了代码大小,并且可以轻松地将字符串恢复为原始视图。建议仅对小型源代码启用此选项。
  35. }
  36. const buildConfig = {
  37. entryPoints: ['src/DC.js'],
  38. bundle: true,
  39. color: true,
  40. legalComments: `inline`,
  41. logLimit: 0,
  42. target: `es2019`,
  43. minify: false,
  44. sourcemap: false,
  45. write: true,
  46. logLevel: 'info',
  47. external: [`http`, `https`, `url`, `zlib`],
  48. plugins: [
  49. inlineImage({
  50. limit: -1,
  51. }),
  52. glsl(),
  53. ],
  54. }
  55. const packageJson = fse.readJsonSync('./package.json')
  56. const plugins = [
  57. resolve({ preferBuiltins: true }),
  58. commonjs(),
  59. babel({
  60. babelHelpers: 'runtime',
  61. presets: [
  62. [
  63. '@babel/preset-env',
  64. {
  65. modules: false,
  66. targets: {
  67. browsers: ['> 1%', 'last 2 versions', 'ie >= 10'],
  68. },
  69. },
  70. ],
  71. ],
  72. plugins: ['@babel/plugin-transform-runtime'],
  73. }),
  74. ]
  75. function getTime() {
  76. let now = new Date()
  77. let m = now.getMonth() + 1
  78. m = m < 10 ? '0' + m : m
  79. let d = now.getDate()
  80. d = d < 10 ? '0' + d : d
  81. return `${now.getFullYear()}-${m}-${d}`
  82. }
  83. async function buildNamespace(options) {
  84. const bundle = await rollup({
  85. input: 'libs/index.js',
  86. plugins: [...plugins, ...[options.dev ? null : terser()]],
  87. onwarn: (message) => {
  88. // Ignore eval warnings in third-party code we don't have control over
  89. if (message.code === 'EVAL' && /protobufjs/.test(message.loc.file)) {
  90. return
  91. }
  92. if (message.code === 'CIRCULAR_DEPENDENCY') {
  93. return
  94. }
  95. console.log(message)
  96. },
  97. })
  98. return bundle.write({
  99. name: 'DC.__namespace',
  100. file: options.node ? 'dist/namespace.cjs' : 'dist/namespace.js',
  101. format: options.node ? 'cjs' : 'umd',
  102. sourcemap: false,
  103. banner: options.node ? '(function(){' : '',
  104. footer: options.node ? '})()' : '',
  105. })
  106. }
  107. async function buildCSS() {
  108. const bundle = await rollup({
  109. input: 'src/themes/index.js',
  110. plugins: [
  111. commonjs(),
  112. resolve({ preferBuiltins: true }),
  113. scss({
  114. outputStyle: 'compressed',
  115. fileName: 'dc.min.css',
  116. }),
  117. ],
  118. })
  119. return bundle.write({
  120. file: 'dist/dc.min.css',
  121. })
  122. }
  123. async function buildModules(options) {
  124. const dcPath = path.join('src', 'DC.js')
  125. const content = await fse.readFile(path.join('src', 'index.js'), 'utf8')
  126. await fse.ensureFile(dcPath)
  127. const exportVersion = `export const VERSION = '${packageJson.version}'`
  128. const cmdOut_content = await fse.readFile(
  129. path.join('src', 'copyright', 'cmdOut.js'),
  130. 'utf8'
  131. )
  132. const exportCmdOut = `
  133. export function __cmdOut() {
  134. ${cmdOut_content
  135. .replace('{{__VERSION__}}', packageJson.version)
  136. .replace('{{__TIME__}}', getTime())
  137. .replace(
  138. '{{__ENGINE_VERSION__}}',
  139. packageJson.devDependencies['@cesium/engine'].replace('^', '')
  140. )
  141. .replace('{{__AUTHOR__}}', packageJson.author)
  142. .replace('{{__HOME_PAGE__}}', packageJson.homepage)
  143. .replace('{{__REPOSITORY__}}', packageJson.repository)}
  144. }`
  145. const exportNamespace = `
  146. export const __namespace = {
  147. Cesium: exports.Cesium,
  148. Supercluster: exports.Supercluster
  149. }
  150. `
  151. // Build IIFE
  152. if (options.iife) {
  153. await fse.outputFile(
  154. dcPath,
  155. `
  156. ${exportVersion}
  157. ${exportCmdOut}
  158. ${content}
  159. `,
  160. {
  161. encoding: 'utf8',
  162. }
  163. )
  164. await esbuild.build({
  165. ...buildConfig,
  166. format: 'iife',
  167. globalName: 'DC',
  168. outfile: path.join('dist', 'modules.js'),
  169. })
  170. }
  171. // Build Node、
  172. if (options.node) {
  173. await fse.outputFile(
  174. dcPath,
  175. `
  176. ${exportNamespace}
  177. ${exportVersion}
  178. ${exportCmdOut}
  179. ${content}
  180. `,
  181. {
  182. encoding: 'utf8',
  183. }
  184. )
  185. await esbuild.build({
  186. ...buildConfig,
  187. format: 'cjs',
  188. platform: 'node',
  189. define: {
  190. TransformStream: 'null',
  191. },
  192. outfile: path.join('dist', 'modules.cjs'),
  193. })
  194. }
  195. // remove DC.js
  196. await fse.remove(dcPath)
  197. }
  198. async function combineJs(options) {
  199. // combine for iife
  200. if (options.iife) {
  201. if (options.obfuscate) {
  202. await gulp
  203. .src('dist/modules.js')
  204. .pipe(javascriptObfuscator(obfuscatorConfig))
  205. .pipe(gulp.src('dist/namespace.js'))
  206. .pipe(concat('dc.min.js'))
  207. .pipe(gulp.dest('dist'))
  208. .on('end', () => {
  209. addCopyright(options)
  210. deleteTempFile(options)
  211. })
  212. } else {
  213. await gulp
  214. .src(['dist/modules.js', 'dist/namespace.js'])
  215. .pipe(concat('dc.min.js'))
  216. .pipe(gulp.dest('dist'))
  217. .on('end', () => {
  218. addCopyright(options)
  219. deleteTempFile(options)
  220. })
  221. }
  222. }
  223. // combine for node
  224. if (options.node) {
  225. if (options.obfuscate) {
  226. await gulp
  227. .src('dist/modules.cjs')
  228. .pipe(javascriptObfuscator(obfuscatorConfig))
  229. .pipe(gulp.dest('dist'))
  230. .on('end', async () => {
  231. await gulp
  232. .src(['dist/namespace.cjs', 'dist/modules.cjs'])
  233. .pipe(concat('index.cjs'))
  234. .pipe(gulp.dest('dist'))
  235. .on('end', () => {
  236. addCopyright(options)
  237. deleteTempFile(options)
  238. })
  239. })
  240. } else {
  241. await gulp
  242. .src(['dist/namespace.cjs', 'dist/modules.cjs'])
  243. .pipe(concat('index.cjs'))
  244. .pipe(gulp.dest('dist'))
  245. .on('end', () => {
  246. addCopyright(options)
  247. deleteTempFile(options)
  248. })
  249. }
  250. }
  251. }
  252. async function copyAssets() {
  253. await fse.emptyDir('dist/resources')
  254. await gulp
  255. .src('./node_modules/@cesium/engine/Build/Workers/**', { nodir: true })
  256. .pipe(gulp.dest('dist/resources/Workers'))
  257. await gulp
  258. .src('./node_modules/@cesium/engine/Source/Assets/**', { nodir: true })
  259. .pipe(gulp.dest('dist/resources/Assets'))
  260. await gulp
  261. .src('./node_modules/@cesium/engine/Source/ThirdParty/**', { nodir: true })
  262. .pipe(gulp.dest('dist/resources/ThirdParty'))
  263. }
  264. async function addCopyright(options) {
  265. let header = await fse.readFile(
  266. path.join('src', 'copyright', 'header.js'),
  267. 'utf8'
  268. )
  269. header = header
  270. .replace('{{__VERSION__}}', packageJson.version)
  271. .replace('{{__AUTHOR__}}', packageJson.author)
  272. .replace('{{__REPOSITORY__}}', packageJson.repository)
  273. if (options.iife) {
  274. let filePath = path.join('dist', 'dc.min.js')
  275. const content = await fse.readFile(filePath, 'utf8')
  276. await fse.outputFile(filePath, `${header}${content}`, { encoding: 'utf8' })
  277. }
  278. if (options.node) {
  279. let filePath = path.join('dist', 'index.cjs')
  280. const content = await fse.readFile(filePath, 'utf8')
  281. await fse.outputFile(filePath, `${header}${content}`, { encoding: 'utf8' })
  282. }
  283. }
  284. async function deleteTempFile(options) {
  285. if (options.iife) {
  286. await gulp
  287. .src(['dist/namespace.js', 'dist/modules.js'], { read: false })
  288. .pipe(clean())
  289. }
  290. if (options.node) {
  291. await gulp
  292. .src(['dist/namespace.cjs', 'dist/modules.cjs'], { read: false })
  293. .pipe(clean())
  294. }
  295. }
  296. async function regenerate(option, content) {
  297. await fse.remove('dist/dc.min.js')
  298. await fse.remove('dist/dc.min.css')
  299. await fse.outputFile(path.join('dist', 'namespace.js'), content)
  300. await buildModules(option)
  301. await combineJs(option)
  302. await buildCSS()
  303. }
  304. export const server = gulp.series(startServer)
  305. export const dev = gulp.series(
  306. () => buildNamespace({ dev: true }),
  307. copyAssets,
  308. () => {
  309. shell.echo(chalk.yellow('============= start dev =============='))
  310. let jsContent = null
  311. const watcher = chokidar.watch('src', {
  312. persistent: true,
  313. awaitWriteFinish: {
  314. stabilityThreshold: 1000,
  315. pollInterval: 100,
  316. },
  317. })
  318. watcher
  319. .on('ready', async () => {
  320. jsContent = fse.readFileSync(path.join('dist', 'namespace.js'), 'utf8')
  321. await regenerate({ iife: true }, jsContent)
  322. await startServer()
  323. })
  324. .on('change', async () => {
  325. let now = new Date().getTime()
  326. if (!jsContent) {
  327. jsContent = fse.readFileSync(
  328. path.join('dist', 'namespace.js'),
  329. 'utf8'
  330. )
  331. }
  332. await regenerate({ iife: true }, jsContent)
  333. shell.echo(
  334. chalk.bgGreen(`regenerate lib takes ${new Date().getTime() - now} ms`)
  335. )
  336. })
  337. return watcher
  338. }
  339. )
  340. export const buildNode = gulp.series(
  341. () => buildNamespace({ node: true }),
  342. () => buildModules({ node: true }),
  343. () => combineJs({ node: true }),
  344. buildCSS,
  345. copyAssets
  346. )
  347. export const buildIIFE = gulp.series(
  348. () => buildNamespace({ iife: true }),
  349. () => buildModules({ iife: true }),
  350. () => combineJs({ iife: true }),
  351. buildCSS,
  352. copyAssets
  353. )
  354. export const build = gulp.series(
  355. () => buildNamespace({ node: true }),
  356. () => buildModules({ node: true }),
  357. () => combineJs({ node: true }),
  358. () => buildNamespace({ iife: true }),
  359. () => buildModules({ iife: true }),
  360. () => combineJs({ iife: true }),
  361. buildCSS,
  362. copyAssets
  363. )
  364. export const buildRelease = gulp.series(
  365. () => buildNamespace({ node: true }),
  366. () => buildModules({ node: true }),
  367. () => combineJs({ node: true, obfuscate: true }),
  368. () => buildNamespace({ iife: true }),
  369. () => buildModules({ iife: true }),
  370. () => combineJs({ iife: true, obfuscate: true }),
  371. buildCSS,
  372. copyAssets
  373. )