diff --git a/.gitignore b/.gitignore index 32c47e020..afb3da5d0 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,10 @@ transifex.auth /dist/*.js /dist/*.css /dist/*.map +/dist/esbuild.json /dist/data/ /dist/img/*.svg +/dist/locales/en.min.json /dist/mapillary-js/ /dist/pannellum-streetside/ @@ -24,4 +26,4 @@ land.html /img /css/img /test/css -/test/img +/test/img \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 16dbce38b..1560ebe5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,15 @@ _Breaking developer changes, which may affect downstream projects or sites that [@xxxx]: https://github.com/xxxx --> + +# Unreleased + +#### :hammer: Development +* Switch build system to [esbuild](https://esbuild.github.io/) for much faster builds ([#8774], thanks [@ mbrzakovic] and [@bhousel]) + +[#8774]: https://github.com/openstreetmap/iD/pull/8774 + + # 2.20.3 ##### 2022-Jan-31 diff --git a/babel.config.json b/babel.config.json index 3be60f4ab..e7b4de4f5 100644 --- a/babel.config.json +++ b/babel.config.json @@ -2,11 +2,21 @@ "presets": [ [ "@babel/preset-env", { - "useBuiltIns": "usage", + "useBuiltIns": "entry", "corejs": 3, - "modules": false + "modules": false, + "targets": { + "chrome": "58", + "ie": 11 + } } ] ], + "plugins": [ + "inline-json-import", + ["@babel/transform-runtime", { + "regenerator": true + }] + ], "compact": false -} +} \ No newline at end of file diff --git a/config/esbuild.config.legacy-min.mjs b/config/esbuild.config.legacy-min.mjs new file mode 100644 index 000000000..e2e2f750b --- /dev/null +++ b/config/esbuild.config.legacy-min.mjs @@ -0,0 +1,24 @@ +import esbuild from 'esbuild'; +import babel from 'esbuild-plugin-babel'; + +esbuild + .build({ + minify: true, + bundle: true, + sourcemap: true, + entryPoints: ['./modules/id.js'], + legalComments: 'none', + logLevel: 'info', + outfile: 'dist/iD.legacy.min.js', + target: 'es5', + plugins: [babel({ + filter: /.*/, + namespace: '', + babelHelpers: 'bundled', + // avoid circular dependencies due to `useBuiltIns: usage` option + exclude: [/\/core-js\//], + sourceType: 'unambiguous', + })], + }) + .catch(() => process.exit(1)); + diff --git a/config/esbuild.config.legacy.mjs b/config/esbuild.config.legacy.mjs new file mode 100644 index 000000000..0fd823911 --- /dev/null +++ b/config/esbuild.config.legacy.mjs @@ -0,0 +1,22 @@ +import esbuild from 'esbuild'; +import babel from 'esbuild-plugin-babel'; + +esbuild + .build({ + bundle: true, + sourcemap: true, + entryPoints: ['./modules/id.js'], + legalComments: 'none', + logLevel: 'info', + outfile: 'dist/iD.legacy.js', + target: 'es5', + plugins: [babel({ + filter: /.*/, + namespace: '', + babelHelpers: 'bundled', + // avoid circular dependencies due to `useBuiltIns: usage` option + exclude: [/\/core-js\//], + sourceType: 'unambiguous', + })], + }) + .catch(() => process.exit(1)); diff --git a/config/esbuild.config.modern-min.mjs b/config/esbuild.config.modern-min.mjs new file mode 100644 index 000000000..ccee45138 --- /dev/null +++ b/config/esbuild.config.modern-min.mjs @@ -0,0 +1,13 @@ +import esbuild from 'esbuild'; + +esbuild + .build({ + minify: true, + bundle: true, + sourcemap: true, + entryPoints: ['./modules/id.js'], + legalComments: 'none', + logLevel: 'info', + outfile: 'dist/iD.min.js' + }) + .catch(() => process.exit(1)); diff --git a/config/esbuild.config.modern.mjs b/config/esbuild.config.modern.mjs new file mode 100644 index 000000000..41bf8452e --- /dev/null +++ b/config/esbuild.config.modern.mjs @@ -0,0 +1,21 @@ +import esbuild from 'esbuild'; +import fs from 'node:fs'; +import parse from 'minimist'; + +let args = parse(process.argv.slice(2), {boolean: true}); +delete args._; + +esbuild + .build(Object.assign({ + bundle: true, + sourcemap: true, + entryPoints: ['./modules/id.js'], + legalComments: 'none', + logLevel: 'info', + metafile: true, + outfile: 'dist/iD.js' + }, args)) + .then(result => { + fs.writeFileSync('./dist/esbuild.json', JSON.stringify(result.metafile, null, 2)); + }) + .catch(() => process.exit(1)); diff --git a/config/rollup.config.dev.js b/config/rollup.config.dev.js deleted file mode 100644 index 687c748cb..000000000 --- a/config/rollup.config.dev.js +++ /dev/null @@ -1,41 +0,0 @@ -/* eslint-disable no-console */ -import commonjs from '@rollup/plugin-commonjs'; -import includePaths from 'rollup-plugin-includepaths'; -import json from '@rollup/plugin-json'; -import nodeResolve from '@rollup/plugin-node-resolve'; -import progress from 'rollup-plugin-progress'; - - -// The "dev" build includes all modules in a single bundle - for now -// * Skips transpilation (so it includes ES6 code and must run in a modern browser) -// * Also generates sourcemaps - -export default { - input: './modules/id.js', - onwarn: onWarn, - output: { - file: 'dist/iD.js', - format: 'iife', - sourcemap: true, - strict: false - }, - plugins: [ - progress(), - includePaths({ - paths: ['node_modules/d3/node_modules'] // npm2 or windows - }), - nodeResolve({ dedupe: ['object-inspect'] }), - commonjs(), - json({ indent: '' }) - ] -}; - -function onWarn(warning, warn) { - // skip certain warnings - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - if (warning.code === 'EVAL') return; - - // Use default for everything else - console.log(warning.code); - warn(warning); -} diff --git a/config/rollup.config.legacy.js b/config/rollup.config.legacy.js deleted file mode 100644 index 8e9ad0df1..000000000 --- a/config/rollup.config.legacy.js +++ /dev/null @@ -1,47 +0,0 @@ -/* eslint-disable no-console */ -import babel from '@rollup/plugin-babel'; -import commonjs from '@rollup/plugin-commonjs'; -import includePaths from 'rollup-plugin-includepaths'; -import json from '@rollup/plugin-json'; -import progress from 'rollup-plugin-progress'; -import nodeResolve from '@rollup/plugin-node-resolve'; - - -// The "legacy" build includes all modules in a single bundle: -// * Runs `buble` to transpile ES6 -> ES5 (needed for IE11 and PhantomJS) -// * No sourcemaps - -export default { - input: './modules/id.js', - onwarn: onWarn, - output: { - file: 'dist/iD.legacy.js', - format: 'iife', - sourcemap: false, - strict: false - }, - plugins: [ - progress(), - includePaths({ - paths: ['node_modules/d3/node_modules'] // npm2 or windows - }), - nodeResolve({ dedupe: ['object-inspect'] }), - commonjs(), - json({ indent: '' }), - babel({ - babelHelpers: 'bundled', - // avoid circular dependencies due to `useBuiltIns: usage` option - exclude: [/\/core-js\//] - }) - ] -}; - -function onWarn(warning, warn) { - // skip certain warnings - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - if (warning.code === 'EVAL') return; - - // Use default for everything else - console.log(warning.code); - warn(warning); -} diff --git a/config/rollup.config.stats.js b/config/rollup.config.stats.js deleted file mode 100644 index 50103e827..000000000 --- a/config/rollup.config.stats.js +++ /dev/null @@ -1,45 +0,0 @@ -/* eslint-disable no-console */ -import commonjs from '@rollup/plugin-commonjs'; -import includePaths from 'rollup-plugin-includepaths'; -import json from '@rollup/plugin-json'; -import nodeResolve from '@rollup/plugin-node-resolve'; -import progress from 'rollup-plugin-progress'; -import visualizer from 'rollup-plugin-visualizer'; - - -// The "stats" build is just like the "dev" build, -// but it includes the visualizer plugin to generate a statistics page (slow) - -export default { - input: './modules/id.js', - onwarn: onWarn, - output: { - file: 'dist/iD.js', - format: 'iife', - sourcemap: true, - strict: false - }, - plugins: [ - progress(), - includePaths({ - paths: ['node_modules/d3/node_modules'] // npm2 or windows - }), - nodeResolve({ dedupe: ['object-inspect'] }), - commonjs(), - json({ indent: '' }), - visualizer({ - filename: 'docs/statistics.html', - sourcemap: true - }) - ] -}; - -function onWarn(warning, warn) { - // skip certain warnings - if (warning.code === 'CIRCULAR_DEPENDENCY') return; - if (warning.code === 'EVAL') return; - - // Use default for everything else - console.log(warning.code); - warn(warning); -} diff --git a/dist/index.html b/dist/index.html index b03476c76..d49cd996c 100644 --- a/dist/index.html +++ b/dist/index.html @@ -32,8 +32,7 @@ newScript.onerror = checkScript; var isIE11 = !!(navigator.userAgent.match(/Trident/) && !navigator.userAgent.match(/MSIE/)); - // currently all minified files are legacy ES5 because of uglifyJS - newScript.src = isIE11 ? 'iD.min.js' : 'iD.min.js'; + newScript.src = isIE11 ? 'iD.legacy.min.js' : 'iD.min.js'; document.getElementsByTagName('head')[0].appendChild(newScript); @@ -69,4 +68,4 @@ } - + \ No newline at end of file diff --git a/package.json b/package.json index 8ae927375..42fc7553e 100644 --- a/package.json +++ b/package.json @@ -12,18 +12,20 @@ ], "license": "ISC", "scripts": { - "all": "npm-run-all -s clean build build:legacy dist", - "build": "npm-run-all -s build:css build:data build:dev", + "all": "run-s clean build build:legacy dist", + "build": "run-s build:css build:data build:modern", "build:css": "node scripts/build_css.js", "build:data": "shx mkdir -p dist/data && node scripts/build_data.js", - "build:dev": "rollup --config config/rollup.config.dev.js", - "build:legacy": "rollup --config config/rollup.config.legacy.js", - "build:stats": "rollup --config config/rollup.config.stats.js", - "clean": "shx rm -f dist/*.js dist/*.map dist/*.css dist/img/*.svg", - "dist": "npm-run-all -p dist:**", + "build:stats": "esbuild-visualizer --metadata dist/esbuild.json --exclude *.png --filename docs/statistics.html", + "build:modern": "node config/esbuild.config.modern.mjs", + "build:modern:watch": "node config/esbuild.config.modern.mjs --watch", + "build:legacy": "node config/esbuild.config.legacy.mjs", + "clean": "shx rm -f dist/esbuild.json dist/*.js dist/*.map dist/*.css dist/img/*.svg", + "dist": "run-p dist:**", "dist:mapillary": "shx mkdir -p dist/mapillary-js && shx cp -R node_modules/mapillary-js/dist/* dist/mapillary-js/", "dist:pannellum": "shx mkdir -p dist/pannellum-streetside && shx cp -R node_modules/pannellum/build/* dist/pannellum-streetside/", - "dist:min:iD": "uglifyjs dist/iD.legacy.js --compress --mangle --output dist/iD.min.js", + "dist:min:modern": "node config/esbuild.config.modern-min.mjs", + "dist:min:legacy": "node config/esbuild.config.legacy-min.mjs", "dist:svg:iD": "svg-sprite --symbol --symbol-dest . --shape-id-generator \"iD-%s\" --symbol-sprite dist/img/iD-sprite.svg \"svg/iD-sprite/**/*.svg\"", "dist:svg:community": "svg-sprite --symbol --symbol-dest . --shape-id-generator \"community-%s\" --symbol-sprite dist/img/community-sprite.svg node_modules/osm-community-index/dist/img/*.svg", "dist:svg:fa": "svg-sprite --symbol --symbol-dest . --symbol-sprite dist/img/fa-sprite.svg svg/fontawesome/*.svg", @@ -34,8 +36,8 @@ "imagery": "node scripts/update_imagery.js", "lint": "eslint scripts test/spec modules", "lint:fix": "eslint scripts test/spec modules --fix", - "start": "npm-run-all -s build start:server", - "quickstart": "npm-run-all -s build:dev start:server", + "start": "run-s build:modern start:server", + "start:watch": "run-p build:modern:watch start:server", "start:server": "node scripts/server.js", "test": "npm-run-all -s lint build test:spec", "test:spec": "karma start karma.conf.js", @@ -52,7 +54,7 @@ "abortcontroller-polyfill": "^1.4.0", "aes-js": "^3.1.2", "alif-toolkit": "^1.2.9", - "core-js": "^3.6.5", + "core-js-bundle": "^3.19.0", "diacritics": "1.3.0", "fast-deep-equal": "~3.1.1", "fast-json-stable-stringify": "2.1.0", @@ -68,19 +70,17 @@ "which-polygon": "2.2.0" }, "devDependencies": { - "@babel/core": "^7.11.6", - "@babel/preset-env": "^7.11.5", + "@babel/core": "^7.15.8", + "@babel/plugin-transform-runtime": "^7.15.8", + "@babel/preset-env": "^7.15.6", "@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/free-brands-svg-icons": "~5.15.1", "@fortawesome/free-regular-svg-icons": "~5.15.1", "@fortawesome/free-solid-svg-icons": "~5.15.1", "@ideditor/temaki": "~5.0.0", "@mapbox/maki": "^6.0.0", - "@rollup/plugin-babel": "^5.2.1", - "@rollup/plugin-commonjs": "^21.0.0", - "@rollup/plugin-json": "^4.0.1", - "@rollup/plugin-node-resolve": "~13.0.5", "autoprefixer": "^10.0.1", + "babel-plugin-inline-json-import": "^0.3.2", "btoa": "^1.2.1", "chai": "^4.3.4", "cldr-core": "37.0.0", @@ -89,6 +89,9 @@ "concat-files": "^0.1.1", "d3": "~6.6.0", "editor-layer-index": "github:osmlab/editor-layer-index#gh-pages", + "esbuild": "^0.13.10", + "esbuild-plugin-babel": "^0.2.3", + "esbuild-visualizer": "^0.3.1", "eslint": "^7.1.0", "fetch-mock": "^9.11.0", "gaze": "^1.1.3", @@ -101,8 +104,8 @@ "karma-coverage": "^2.0.3", "karma-mocha": "^2.0.1", "karma-remap-istanbul": "^0.6.0", - "mapillary_sprite_source": "^1.8.0", "mapillary-js": "4.0.0", + "mapillary_sprite_source": "^1.8.0", "minimist": "^1.2.3", "mocha": "^8.4.0", "name-suggestion-index": "~6.0", @@ -112,10 +115,6 @@ "osm-community-index": "~5.1.0", "postcss": "^8.1.1", "postcss-selector-prepend": "^0.5.0", - "rollup": "~2.52.8", - "rollup-plugin-includepaths": "~0.2.3", - "rollup-plugin-progress": "^1.1.1", - "rollup-plugin-visualizer": "~4.2.0", "shelljs": "^0.8.0", "shx": "^0.3.0", "sinon": "^11.1.2", @@ -123,7 +122,6 @@ "smash": "0.0", "static-server": "^2.2.1", "svg-sprite": "1.5.1", - "uglify-js": "~3.13.0", "vparse": "~1.1.0" }, "engines": {