From c301d2413ba87266bc759ad24d36b5c8701ae9d1 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 20 Feb 2020 18:30:09 -0700 Subject: [PATCH] Modules all the way --- .nvmrc | 1 + config/jsdoc/api/conf.json | 10 +-- config/jsdoc/api/plugins/{api.js => api.cjs} | 2 + .../api/plugins/{events.js => events.cjs} | 2 + .../{inline-options.js => inline-options.cjs} | 2 + .../api/plugins/{markdown.js => markdown.cjs} | 2 + .../plugins/{observable.js => observable.cjs} | 2 + config/jsdoc/api/template/publish.js | 2 + config/jsdoc/info/conf.json | 4 +- .../{define-plugin.js => define-plugin.cjs} | 2 + config/jsdoc/info/publish.js | 2 + .../{virtual-plugin.js => virtual-plugin.cjs} | 2 + config/jsdoc/package.json | 4 + config/webpack-config-legacy-build.js | 11 ++- examples/webpack/.eslintrc | 7 -- examples/webpack/config.js | 33 ++++---- examples/webpack/example-builder.js | 56 +++++++++----- .../{worker-loader.js => worker-loader.cjs} | 10 +-- package-lock.json | 62 ++++++++++++++- package.json | 19 +++-- tasks/generate-index.js | 26 +++---- tasks/generate-info.js | 42 +++++----- tasks/next-dev-version.js | 21 +++-- tasks/prepare-package.js | 76 +++++++++++-------- ...alize-workers.js => serialize-workers.cjs} | 2 + test/browser/index_test.js | 5 -- .../{karma.config.js => karma.config.cjs} | 7 +- test/rendering/test.js | 54 +++++++------ test/rendering/webpack.config.js | 21 ++--- 29 files changed, 316 insertions(+), 173 deletions(-) create mode 100644 .nvmrc rename config/jsdoc/api/plugins/{api.js => api.cjs} (99%) rename config/jsdoc/api/plugins/{events.js => events.cjs} (95%) rename config/jsdoc/api/plugins/{inline-options.js => inline-options.cjs} (97%) rename config/jsdoc/api/plugins/{markdown.js => markdown.cjs} (98%) rename config/jsdoc/api/plugins/{observable.js => observable.cjs} (98%) rename config/jsdoc/info/{define-plugin.js => define-plugin.cjs} (95%) rename config/jsdoc/info/{virtual-plugin.js => virtual-plugin.cjs} (90%) create mode 100644 config/jsdoc/package.json rename examples/webpack/{worker-loader.js => worker-loader.cjs} (66%) rename tasks/{serialize-workers.js => serialize-workers.cjs} (98%) delete mode 100644 test/browser/index_test.js rename test/browser/{karma.config.js => karma.config.cjs} (94%) diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000..b6a7d89c68 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +16 diff --git a/config/jsdoc/api/conf.json b/config/jsdoc/api/conf.json index 2a2f328b2b..8fb5978971 100644 --- a/config/jsdoc/api/conf.json +++ b/config/jsdoc/api/conf.json @@ -14,12 +14,12 @@ ] }, "plugins": [ - "config/jsdoc/api/plugins/markdown", + "config/jsdoc/api/plugins/markdown.cjs", "jsdoc-plugin-typescript", - "config/jsdoc/api/plugins/inline-options", - "config/jsdoc/api/plugins/events", - "config/jsdoc/api/plugins/observable", - "config/jsdoc/api/plugins/api" + "config/jsdoc/api/plugins/inline-options.cjs", + "config/jsdoc/api/plugins/events.cjs", + "config/jsdoc/api/plugins/observable.cjs", + "config/jsdoc/api/plugins/api.cjs" ], "typescript": { "moduleRoot": "src" diff --git a/config/jsdoc/api/plugins/api.js b/config/jsdoc/api/plugins/api.cjs similarity index 99% rename from config/jsdoc/api/plugins/api.js rename to config/jsdoc/api/plugins/api.cjs index 10184ea7bd..5a91e76a27 100644 --- a/config/jsdoc/api/plugins/api.js +++ b/config/jsdoc/api/plugins/api.cjs @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + /** * Define an @api tag * @param {Object} dictionary The tag dictionary. diff --git a/config/jsdoc/api/plugins/events.js b/config/jsdoc/api/plugins/events.cjs similarity index 95% rename from config/jsdoc/api/plugins/events.js rename to config/jsdoc/api/plugins/events.cjs index 6ce80dd5e2..fcacbacbd7 100644 --- a/config/jsdoc/api/plugins/events.js +++ b/config/jsdoc/api/plugins/events.cjs @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + const events = {}; exports.handlers = { diff --git a/config/jsdoc/api/plugins/inline-options.js b/config/jsdoc/api/plugins/inline-options.cjs similarity index 97% rename from config/jsdoc/api/plugins/inline-options.js rename to config/jsdoc/api/plugins/inline-options.cjs index 72511a7d18..61bd7e5990 100644 --- a/config/jsdoc/api/plugins/inline-options.js +++ b/config/jsdoc/api/plugins/inline-options.cjs @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + /** * @fileoverview * Inlines option params from typedefs diff --git a/config/jsdoc/api/plugins/markdown.js b/config/jsdoc/api/plugins/markdown.cjs similarity index 98% rename from config/jsdoc/api/plugins/markdown.js rename to config/jsdoc/api/plugins/markdown.cjs index 3d7da8869a..289ecf71cc 100644 --- a/config/jsdoc/api/plugins/markdown.js +++ b/config/jsdoc/api/plugins/markdown.cjs @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + /** * Modified from JSDoc's plugins/markdown and lib/jsdoc/util/markdown modules * (see https://github.com/jsdoc3/jsdoc/), which are licensed under the Apache 2 diff --git a/config/jsdoc/api/plugins/observable.js b/config/jsdoc/api/plugins/observable.cjs similarity index 98% rename from config/jsdoc/api/plugins/observable.js rename to config/jsdoc/api/plugins/observable.cjs index 27ccb5f14e..f3ffcff9bc 100644 --- a/config/jsdoc/api/plugins/observable.js +++ b/config/jsdoc/api/plugins/observable.cjs @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + const classes = {}; const observables = {}; diff --git a/config/jsdoc/api/template/publish.js b/config/jsdoc/api/template/publish.js index f750010173..7a70ec63a3 100644 --- a/config/jsdoc/api/template/publish.js +++ b/config/jsdoc/api/template/publish.js @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + /*global env: true */ const hasOwnProp = Object.prototype.hasOwnProperty; diff --git a/config/jsdoc/info/conf.json b/config/jsdoc/info/conf.json index 969ae716c0..2997676be2 100644 --- a/config/jsdoc/info/conf.json +++ b/config/jsdoc/info/conf.json @@ -11,8 +11,8 @@ }, "plugins": [ "jsdoc-plugin-typescript", - "config/jsdoc/info/define-plugin", - "config/jsdoc/info/virtual-plugin" + "config/jsdoc/info/define-plugin.cjs", + "config/jsdoc/info/virtual-plugin.cjs" ], "typescript": { "moduleRoot": "src" diff --git a/config/jsdoc/info/define-plugin.js b/config/jsdoc/info/define-plugin.cjs similarity index 95% rename from config/jsdoc/info/define-plugin.js rename to config/jsdoc/info/define-plugin.cjs index 3d604db19a..c7d3ca3fed 100644 --- a/config/jsdoc/info/define-plugin.js +++ b/config/jsdoc/info/define-plugin.cjs @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + /** * @fileoverview This plugin extracts info from boolean defines. This only * handles boolean defines with the default value in the description. Default diff --git a/config/jsdoc/info/publish.js b/config/jsdoc/info/publish.js index 188ddf4ad2..99b1b6b8d0 100644 --- a/config/jsdoc/info/publish.js +++ b/config/jsdoc/info/publish.js @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + /** * @fileoverview Generates JSON output based on exportable symbols. */ diff --git a/config/jsdoc/info/virtual-plugin.js b/config/jsdoc/info/virtual-plugin.cjs similarity index 90% rename from config/jsdoc/info/virtual-plugin.js rename to config/jsdoc/info/virtual-plugin.cjs index f83a2dba26..78badcfe79 100644 --- a/config/jsdoc/info/virtual-plugin.js +++ b/config/jsdoc/info/virtual-plugin.cjs @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + /** * Handle the interface and abstract annotations. * @param {Object} dictionary The tag dictionary. diff --git a/config/jsdoc/package.json b/config/jsdoc/package.json new file mode 100644 index 0000000000..6aea923e82 --- /dev/null +++ b/config/jsdoc/package.json @@ -0,0 +1,4 @@ +{ + "description": "JSDoc loads publish.js files with require(), so we need to configure everything under this path as a CommonJS module.", + "type": "commonjs" +} \ No newline at end of file diff --git a/config/webpack-config-legacy-build.js b/config/webpack-config-legacy-build.js index 7418089a48..89786cf0a0 100644 --- a/config/webpack-config-legacy-build.js +++ b/config/webpack-config-legacy-build.js @@ -1,7 +1,10 @@ -const path = require('path'); -const TerserPlugin = require('terser-webpack-plugin'); +import TerserPlugin from 'terser-webpack-plugin'; +import path, {dirname} from 'path'; +import {fileURLToPath} from 'url'; -module.exports = { +const baseDir = dirname(fileURLToPath(import.meta.url)); + +export default { entry: './build/index.js', devtool: 'source-map', mode: 'production', @@ -18,7 +21,7 @@ module.exports = { }, include: [ path.join( - __dirname, + baseDir, '..', 'node_modules', '@mapbox', diff --git a/examples/webpack/.eslintrc b/examples/webpack/.eslintrc index 92ab127997..4697ff0ee2 100644 --- a/examples/webpack/.eslintrc +++ b/examples/webpack/.eslintrc @@ -5,12 +5,5 @@ }, "parserOptions": { "ecmaVersion": 2017 - }, - "rules": { - "space-before-function-paren": ["error", { - "anonymous": "never", - "named": "never", - "asyncArrow": "always" - }] } } diff --git a/examples/webpack/config.js b/examples/webpack/config.js index b638ce019b..4f02305c56 100644 --- a/examples/webpack/config.js +++ b/examples/webpack/config.js @@ -1,12 +1,15 @@ -const TerserPlugin = require('terser-webpack-plugin'); -const CopyPlugin = require('copy-webpack-plugin'); -const ExampleBuilder = require('./example-builder'); -const fs = require('fs'); -const path = require('path'); +import CopyPlugin from 'copy-webpack-plugin'; +import ExampleBuilder from './example-builder.js'; +import TerserPlugin from 'terser-webpack-plugin'; +import fs from 'fs'; +import path, {dirname} from 'path'; +import {fileURLToPath} from 'url'; -const src = path.join(__dirname, '..'); +const baseDir = dirname(fileURLToPath(import.meta.url)); -module.exports = { +const src = path.join(baseDir, '..'); + +export default { context: src, target: ['web', 'es5'], entry: () => { @@ -33,10 +36,10 @@ module.exports = { }, }, include: [ - path.join(__dirname, '..', '..', 'src'), - path.join(__dirname, '..'), + path.join(baseDir, '..', '..', 'src'), + path.join(baseDir, '..'), path.join( - __dirname, + baseDir, '..', '..', 'node_modules', @@ -48,9 +51,9 @@ module.exports = { { test: /\.js$/, use: { - loader: path.join(__dirname, 'worker-loader.js'), + loader: path.join(baseDir, 'worker-loader.cjs'), }, - include: [path.join(__dirname, '..', '..', 'src', 'ol', 'worker')], + include: [path.join(baseDir, '..', '..', 'src', 'ol', 'worker')], }, ], }, @@ -77,7 +80,7 @@ module.exports = { }, plugins: [ new ExampleBuilder({ - templates: path.join(__dirname, '..', 'templates'), + templates: path.join(baseDir, '..', 'templates'), common: 'common', }), new CopyPlugin({ @@ -93,7 +96,7 @@ module.exports = { devtool: 'source-map', output: { filename: '[name].js', - path: path.join(__dirname, '..', '..', 'build', 'examples'), + path: path.join(baseDir, '..', '..', 'build', 'examples'), }, resolve: { fallback: { @@ -101,7 +104,7 @@ module.exports = { }, alias: { // allow imports from 'ol/module' instead of specifiying the source path - ol: path.join(__dirname, '..', '..', 'src', 'ol'), + ol: path.join(baseDir, '..', '..', 'src', 'ol'), }, }, }; diff --git a/examples/webpack/example-builder.js b/examples/webpack/example-builder.js index c41334f606..41e6bdbd06 100644 --- a/examples/webpack/example-builder.js +++ b/examples/webpack/example-builder.js @@ -1,20 +1,32 @@ -const assert = require('assert'); -const frontMatter = require('front-matter'); -const fs = require('fs'); -const handlebars = require('handlebars'); -const marked = require('marked'); -const path = require('path'); -const pkg = require('../../package.json'); -const promisify = require('util').promisify; -const RawSource = require('webpack-sources').RawSource; +import assert from 'assert'; +import frontMatter from 'front-matter'; +import fse from 'fs-extra'; +import handlebars from 'handlebars'; +import marked from 'marked'; +import path, {dirname} from 'path'; +import sources from 'webpack-sources'; +import {fileURLToPath} from 'url'; + +const RawSource = sources.RawSource; +const baseDir = dirname(fileURLToPath(import.meta.url)); -const readFile = promisify(fs.readFile); const isCssRegEx = /\.css(\?.*)?$/; const isJsRegEx = /\.js(\?.*)?$/; const importRegEx = /^import .* from '(.*)';$/; const isTemplateJs = /\/(jquery(-\d+\.\d+\.\d+)?|(bootstrap(\.bundle)?))(\.min)?\.js(\?.*)?$/; const isTemplateCss = /\/bootstrap(\.min)?\.css(\?.*)?$/; +let cachedPackageInfo = null; +async function getPackageInfo() { + if (cachedPackageInfo) { + return cachedPackageInfo; + } + cachedPackageInfo = await fse.readJSON( + path.resolve(baseDir, '../../package.json') + ); + return cachedPackageInfo; +} + handlebars.registerHelper( 'md', (str) => new handlebars.SafeString(marked(str)) @@ -111,9 +123,10 @@ function createWordIndex(exampleData) { /** * Gets dependencies from the js source. * @param {string} jsSource Source. + * @param {Object} pkg Package info. * @return {Object} dependencies */ -function getDependencies(jsSource) { +function getDependencies(jsSource, pkg) { const lines = jsSource.split('\n'); const dependencies = { ol: pkg.version, @@ -140,7 +153,7 @@ function getDependencies(jsSource) { return dependencies; } -class ExampleBuilder { +export default class ExampleBuilder { /** * A webpack plugin that builds the html files for our examples. * @param {Object} config Plugin configuration. Requires a `templates` property @@ -241,16 +254,17 @@ class ExampleBuilder { async parseExample(dir, name) { const htmlName = `${name}.html`; const htmlPath = path.join(dir, htmlName); - const htmlSource = await readFile(htmlPath, {encoding: 'utf8'}); + const htmlSource = await fse.readFile(htmlPath, {encoding: 'utf8'}); const jsName = `${name}.js`; const jsPath = path.join(dir, jsName); - const jsSource = await readFile(jsPath, {encoding: 'utf8'}); + const jsSource = await fse.readFile(jsPath, {encoding: 'utf8'}); const {attributes, body} = frontMatter(htmlSource); assert(!!attributes.layout, `missing layout in ${htmlPath}`); const data = Object.assign(attributes, {contents: body}); + const pkg = await getPackageInfo(); data.olVersion = pkg.version; data.filename = htmlName; data.dir = dir; @@ -299,7 +313,7 @@ class ExampleBuilder { const workerPath = path.join(data.dir, workerName); let workerSource; try { - workerSource = await readFile(workerPath, readOptions); + workerSource = await fse.readFile(workerPath, readOptions); } catch (err) { // pass } @@ -321,11 +335,14 @@ class ExampleBuilder { assets[workerName] = workerSource; } + const pkg = await getPackageInfo(); + data.pkgJson = JSON.stringify( { name: data.name, dependencies: getDependencies( - jsSource + (workerSource ? `\n${workerSource}` : '') + jsSource + (workerSource ? `\n${workerSource}` : ''), + pkg ), devDependencies: { parcel: '^2.0.0-beta.1', @@ -344,7 +361,7 @@ class ExampleBuilder { const cssPath = path.join(data.dir, cssName); let cssSource; try { - cssSource = await readFile(cssPath, readOptions); + cssSource = await fse.readFile(cssPath, readOptions); } catch (err) { // pass } @@ -358,6 +375,7 @@ class ExampleBuilder { // add additional resources if (data.resources) { + const pkg = await getPackageInfo(); const localResources = []; const remoteResources = []; data.resources.forEach((resource) => { @@ -389,11 +407,9 @@ class ExampleBuilder { } const templatePath = path.join(this.templates, data.layout); - const templateSource = await readFile(templatePath, readOptions); + const templateSource = await fse.readFile(templatePath, readOptions); assets[data.filename] = handlebars.compile(templateSource)(data); return assets; } } - -module.exports = ExampleBuilder; diff --git a/examples/webpack/worker-loader.js b/examples/webpack/worker-loader.cjs similarity index 66% rename from examples/webpack/worker-loader.js rename to examples/webpack/worker-loader.cjs index cdaa577f07..15128ea840 100644 --- a/examples/webpack/worker-loader.js +++ b/examples/webpack/worker-loader.cjs @@ -1,6 +1,8 @@ -const build = require('../../tasks/serialize-workers').build; +/* eslint-disable import/no-commonjs */ -function loader() { +const build = require('../../tasks/serialize-workers.cjs').build; + +module.exports = function loader() { const callback = this.async(); const minify = this.mode === 'production'; @@ -12,6 +14,4 @@ function loader() { callback(null, chunk.code); }) .catch(callback); -} - -module.exports = loader; +}; diff --git a/package-lock.json b/package-lock.json index aa721ab673..38eb5e00f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ }, "devDependencies": { "@babel/core": "^7.6.4", + "@babel/eslint-parser": "^7.13.14", "@babel/preset-env": "^7.4.4", "@openlayers/eslint-plugin": "^4.0.0", "@rollup/plugin-babel": "^5.3.0", @@ -32,6 +33,7 @@ "copy-webpack-plugin": "^8.0.0", "coverage-istanbul-loader": "^3.0.5", "coveralls": "3.1.0", + "es-main": "^1.0.2", "eslint": "^7.2.0", "eslint-config-openlayers": "^15.0.0", "expect.js": "0.3.1", @@ -66,7 +68,7 @@ "shx": "^0.3.2", "sinon": "^10.0.0", "terser-webpack-plugin": "^5.1.1", - "typescript": "^4.2.3", + "typescript": "^4.2.4", "url-polyfill": "^1.1.5", "walk": "^2.3.9", "webpack": "^5.27.2", @@ -127,6 +129,33 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/eslint-parser": { + "version": "7.13.14", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.13.14.tgz", + "integrity": "sha512-I0HweR36D73Ibn/FfrRDMKlMqJHFwidIUgYdMpH+aXYuQC+waq59YaJ6t9e9N36axJ82v1jR041wwqDrDXEwRA==", + "dev": true, + "dependencies": { + "eslint-scope": "^5.1.0", + "eslint-visitor-keys": "^1.3.0", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.11.0", + "eslint": ">=7.5.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/generator": { "version": "7.13.16", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.16.tgz", @@ -3631,6 +3660,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-main": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-main/-/es-main-1.0.2.tgz", + "integrity": "sha512-LLgW8Cby/FiyQygrI23q2EswulHiDKoyjWlDRgTGXjQ3iRim2R26VfoehpxI5oKRXSNams3L/80KtggoUdxdDQ==", + "dev": true + }, "node_modules/es-module-lexer": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", @@ -11410,6 +11445,25 @@ "source-map": "^0.5.0" } }, + "@babel/eslint-parser": { + "version": "7.13.14", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.13.14.tgz", + "integrity": "sha512-I0HweR36D73Ibn/FfrRDMKlMqJHFwidIUgYdMpH+aXYuQC+waq59YaJ6t9e9N36axJ82v1jR041wwqDrDXEwRA==", + "dev": true, + "requires": { + "eslint-scope": "^5.1.0", + "eslint-visitor-keys": "^1.3.0", + "semver": "^6.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, "@babel/generator": { "version": "7.13.16", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.16.tgz", @@ -14260,6 +14314,12 @@ "unbox-primitive": "^1.0.0" } }, + "es-main": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-main/-/es-main-1.0.2.tgz", + "integrity": "sha512-LLgW8Cby/FiyQygrI23q2EswulHiDKoyjWlDRgTGXjQ3iRim2R26VfoehpxI5oKRXSNams3L/80KtggoUdxdDQ==", + "dev": true + }, "es-module-lexer": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", diff --git a/package.json b/package.json index 238c89bfb5..295dc4712c 100644 --- a/package.json +++ b/package.json @@ -15,21 +15,21 @@ "test-rendering": "node test/rendering/test.js", "test-spec": "npm run karma -- --single-run --log-level error", "test": "npm run test-spec && npm run test-rendering -- --force", - "karma": "karma start test/browser/karma.config.js", + "karma": "karma start test/browser/karma.config.cjs", "start": "npm run serve-examples", "serve-examples": "webpack serve --config examples/webpack/config.js --mode development", "build-examples": "webpack --config examples/webpack/config.js --mode production", - "build-package": "npm run transpile && npm run copy-css && node tasks/prepare-package", - "build-index": "npm run build-package && node tasks/generate-index", + "build-package": "npm run transpile && npm run copy-css && node tasks/prepare-package.js", + "build-index": "npm run build-package && node tasks/generate-index.js", "build-legacy": "shx rm -rf build && npm run build-index && webpack --config config/webpack-config-legacy-build.js && cleancss --source-map src/ol/ol.css -o build/legacy/ol.css", "build-site": "npm run build-examples && npm run apidoc && mkdir -p build/site && cp site/index.html build/site && mv build/apidoc build/site/apidoc && mv build/examples build/site/examples", "copy-css": "shx cp src/ol/ol.css build/ol/ol.css", - "transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && node tasks/serialize-workers && tsc --project config/tsconfig-build.json", + "transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && node tasks/serialize-workers.cjs && tsc --project config/tsconfig-build.json", "typecheck": "tsc --pretty", "apidoc-debug": "shx rm -rf build/apidoc && node --inspect-brk=9229 ./node_modules/jsdoc/jsdoc.js -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc", "apidoc": "shx rm -rf build/apidoc && jsdoc -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc" }, - "main": "index.js", + "type": "module", "repository": { "type": "git", "url": "git://github.com/openlayers/openlayers.git" @@ -49,6 +49,7 @@ }, "devDependencies": { "@babel/core": "^7.6.4", + "@babel/eslint-parser": "^7.13.14", "@babel/preset-env": "^7.4.4", "@openlayers/eslint-plugin": "^4.0.0", "@rollup/plugin-babel": "^5.3.0", @@ -66,6 +67,7 @@ "copy-webpack-plugin": "^8.0.0", "coverage-istanbul-loader": "^3.0.5", "coveralls": "3.1.0", + "es-main": "^1.0.2", "eslint": "^7.2.0", "eslint-config-openlayers": "^15.0.0", "expect.js": "0.3.1", @@ -100,7 +102,7 @@ "shx": "^0.3.2", "sinon": "^10.0.0", "terser-webpack-plugin": "^5.1.1", - "typescript": "^4.2.3", + "typescript": "^4.2.4", "url-polyfill": "^1.1.5", "walk": "^2.3.9", "webpack": "^5.27.2", @@ -113,10 +115,15 @@ }, "eslintConfig": { "extends": "openlayers", + "parser": "@babel/eslint-parser", + "parserOptions": { + "requireConfigFile": false + }, "plugins": [ "@openlayers" ], "rules": { + "import/no-commonjs": "error", "@openlayers/no-exclusive-tests": [ "error", { diff --git a/tasks/generate-index.js b/tasks/generate-index.js index 37537fcf20..c3e12f5acd 100644 --- a/tasks/generate-index.js +++ b/tasks/generate-index.js @@ -1,6 +1,9 @@ -const fse = require('fs-extra'); -const path = require('path'); -const generateInfo = require('./generate-info'); +import esMain from 'es-main'; +import fse from 'fs-extra'; +import generateInfo from './generate-info.js'; +import path from 'path'; +import {dirname} from 'path'; +import {fileURLToPath} from 'url'; /** * Read the symbols from info file. @@ -21,11 +24,11 @@ function getImport(symbol, member) { const defaultExport = symbol.name.split('~'); const namedExport = symbol.name.split('.'); if (defaultExport.length > 1 && defaultExport[0].indexOf('.') === -1) { - const from = defaultExport[0].replace(/^module\:/, './'); + const from = defaultExport[0].replace(/^module\:/, './') + '.js'; const importName = from.replace(/[.\/]+/g, '$'); return `import ${importName} from '${from}';`; } else if (namedExport.length > 1 && member) { - const from = namedExport[0].replace(/^module\:/, './'); + const from = namedExport[0].replace(/^module\:/, './') + '.js'; const importName = from.replace(/[.\/]+/g, '_'); return `import {${member} as ${importName}$${member}} from '${from}';`; } @@ -97,7 +100,7 @@ function generateExports(symbols) { * Generate the exports code. * @return {Promise} Resolves with the exports code. */ -async function main() { +export default async function main() { const symbols = await getSymbols(); return generateExports(symbols); } @@ -106,18 +109,15 @@ async function main() { * If running this module directly, read the config file, call the main * function, and write the output file. */ -if (require.main === module) { +if (esMain(import.meta)) { + const baseDir = dirname(fileURLToPath(import.meta.url)); + main() .then(async (code) => { - const filepath = path.join(__dirname, '..', 'build', 'index.js'); + const filepath = path.join(baseDir, '..', 'build', 'index.js'); await fse.outputFile(filepath, code); }) .catch((err) => { process.stderr.write(`${err.message}\n`, () => process.exit(1)); }); } - -/** - * Export main function. - */ -module.exports = main; diff --git a/tasks/generate-info.js b/tasks/generate-info.js index a5d0fed440..c011f1448f 100644 --- a/tasks/generate-info.js +++ b/tasks/generate-info.js @@ -1,11 +1,16 @@ -const fse = require('fs-extra'); -const path = require('path'); -const spawn = require('child_process').spawn; -const walk = require('walk').walk; -const isWindows = process.platform.indexOf('win') === 0; +import esMain from 'es-main'; +import fse from 'fs-extra'; +import path from 'path'; +import {dirname} from 'path'; +import {fileURLToPath} from 'url'; +import {spawn} from 'child_process'; +import {walk} from 'walk'; -const sourceDir = path.join(__dirname, '..', 'src'); -const infoPath = path.join(__dirname, '..', 'build', 'info.json'); +const isWindows = process.platform.indexOf('win') === 0; +const baseDir = dirname(fileURLToPath(import.meta.url)); + +const sourceDir = path.join(baseDir, '..', 'src'); +const infoPath = path.join(baseDir, '..', 'build', 'info.json'); /** * Get checked path of a binary. @@ -17,9 +22,15 @@ function getBinaryPath(binaryName) { binaryName += '.cmd'; } - const jsdocResolved = require.resolve('jsdoc/jsdoc.js'); + const jsdocResolved = path.join( + baseDir, + '..', + 'node_modules', + 'jsdoc', + 'jsdoc.js' + ); const expectedPaths = [ - path.join(__dirname, '..', 'node_modules', '.bin', binaryName), + path.join(baseDir, '..', 'node_modules', '.bin', binaryName), path.resolve( path.join(path.dirname(jsdocResolved), '..', '.bin', binaryName) ), @@ -40,7 +51,7 @@ function getBinaryPath(binaryName) { const jsdoc = getBinaryPath('jsdoc'); const jsdocConfig = path.join( - __dirname, + baseDir, '..', 'config', 'jsdoc', @@ -120,7 +131,7 @@ function spawnJSDoc(paths) { return new Promise((resolve, reject) => { let output = ''; let errors = ''; - const cwd = path.join(__dirname, '..'); + const cwd = path.join(baseDir, '..'); const child = spawn(jsdoc, ['-c', jsdocConfig].concat(paths), {cwd: cwd}); child.stdout.on('data', (data) => { @@ -162,7 +173,7 @@ async function write(info) { * Generate info from the sources. * @return {Promise} Resolves with the info object. */ -async function main() { +export default async function main() { const paths = await getPaths(); return await spawnJSDoc(paths); } @@ -170,15 +181,10 @@ async function main() { /** * If running this module directly, generate and write out the info.json file. */ -if (require.main === module) { +if (esMain(import.meta)) { main() .then(write) .catch((err) => { process.stderr.write(`${err.message}\n`, () => process.exit(1)); }); } - -/** - * Export main function. - */ -module.exports = main; diff --git a/tasks/next-dev-version.js b/tasks/next-dev-version.js index 02f1c5b647..35bc42d5f1 100644 --- a/tasks/next-dev-version.js +++ b/tasks/next-dev-version.js @@ -1,7 +1,11 @@ -const version = require('../package.json').version; -const semver = require('semver'); +import esMain from 'es-main'; +import process from 'process'; +import semver from 'semver'; +import {promises as fs} from 'fs'; -function nextVersion() { +async function nextVersion() { + const pkg = await fs.readFile('../package.json', {encoding: 'utf8'}); + const version = JSON.parse(pkg).version; const s = semver.parse(version); if (!s) { throw new Error(`Invalid version ${version}`); @@ -9,6 +13,13 @@ function nextVersion() { return `${s.major}.${s.minor}.${s.patch}-dev.${Date.now()}`; } -if (require.main === module) { - process.stdout.write(`${nextVersion()}\n`); +if (esMain(import.meta)) { + nextVersion() + .then((version) => { + process.stdout.write(`${version}\n`); + }) + .catch((error) => { + process.stderr.write(`${error}\n`); + process.exit(1); + }); } diff --git a/tasks/prepare-package.js b/tasks/prepare-package.js index bcf418c7b9..a49f0a2d31 100644 --- a/tasks/prepare-package.js +++ b/tasks/prepare-package.js @@ -1,35 +1,49 @@ -const fs = require('fs'); -const path = require('path'); -const pkg = require('../package.json'); +import esMain from 'es-main'; +import fse from 'fs-extra'; +import path from 'path'; +import {dirname} from 'path'; +import {fileURLToPath} from 'url'; -const buildDir = path.resolve(__dirname, '../build/ol'); +const baseDir = dirname(fileURLToPath(import.meta.url)); +const buildDir = path.resolve(baseDir, '../build/ol'); -// update the version number in util.js -const utilPath = path.join(buildDir, 'util.js'); -const versionRegEx = /var VERSION = '(.*)';/g; -const utilSrc = fs - .readFileSync(utilPath, 'utf-8') - .replace(versionRegEx, `var VERSION = '${pkg.version}';`); -fs.writeFileSync(utilPath, utilSrc, 'utf-8'); +async function main() { + const pkg = await fse.readJSON(path.resolve(baseDir, '../package.json')); -// write out simplified package.json -delete pkg.scripts; -delete pkg.devDependencies; -delete pkg.style; -delete pkg.eslintConfig; -delete pkg.private; -fs.writeFileSync( - path.join(buildDir, 'package.json'), - JSON.stringify(pkg, null, 2), - 'utf-8' -); + // update the version number in util.js + const utilPath = path.join(buildDir, 'util.js'); + const versionRegEx = /var VERSION = '(.*)';/g; + let utilSrc = await fse.readFile(utilPath, 'utf-8'); + utilSrc = utilSrc.replace(versionRegEx, `var VERSION = '${pkg.version}';`); + await fse.writeFile(utilPath, utilSrc, 'utf-8'); -// copy in readme and license files -fs.copyFileSync( - path.resolve(__dirname, '../README.md'), - path.join(buildDir, 'README.md') -); -fs.copyFileSync( - path.resolve(__dirname, '../LICENSE.md'), - path.join(buildDir, 'LICENSE.md') -); + // write out simplified package.json + pkg.main = 'index.js'; + delete pkg.scripts; + delete pkg.devDependencies; + delete pkg.style; + delete pkg.eslintConfig; + delete pkg.private; + await fse.writeJSON(path.join(buildDir, 'package.json'), pkg, {spaces: 2}); + + // copy in readme and license files + await fse.copyFile( + path.resolve(baseDir, '../README.md'), + path.join(buildDir, 'README.md') + ); + + await fse.copyFile( + path.resolve(baseDir, '../LICENSE.md'), + path.join(buildDir, 'LICENSE.md') + ); +} + +/** + * If running this module directly, read the config file, call the main + * function, and write the output file. + */ +if (esMain(import.meta)) { + main().catch((err) => { + process.stderr.write(`${err.message}\n`, () => process.exit(1)); + }); +} diff --git a/tasks/serialize-workers.js b/tasks/serialize-workers.cjs similarity index 98% rename from tasks/serialize-workers.js rename to tasks/serialize-workers.cjs index f4aa1c2a88..3377cfeda6 100644 --- a/tasks/serialize-workers.js +++ b/tasks/serialize-workers.cjs @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + const path = require('path'); const babel = require('@rollup/plugin-babel').babel; const resolve = require('@rollup/plugin-node-resolve').nodeResolve; diff --git a/test/browser/index_test.js b/test/browser/index_test.js deleted file mode 100644 index 504e1d8b51..0000000000 --- a/test/browser/index_test.js +++ /dev/null @@ -1,5 +0,0 @@ -// require all modules ending in ".test.js" from the -// current directory and all subdirectories -const testsContext = require.context('./spec', true, /\.test\.js$/); - -testsContext.keys().forEach(testsContext); diff --git a/test/browser/karma.config.js b/test/browser/karma.config.cjs similarity index 94% rename from test/browser/karma.config.js rename to test/browser/karma.config.cjs index 2e84ea69cc..296d201efe 100644 --- a/test/browser/karma.config.js +++ b/test/browser/karma.config.cjs @@ -1,3 +1,5 @@ +/* eslint-disable import/no-commonjs */ + const path = require('path'); module.exports = function (karma) { @@ -45,7 +47,7 @@ module.exports = function (karma) { pattern: path.resolve(__dirname, './test-extensions.js'), }, { - pattern: path.resolve(__dirname, './index_test.js'), + pattern: 'spec/**/*.test.js', watched: false, }, { @@ -54,7 +56,6 @@ module.exports = function (karma) { watched: false, }, ], - exclude: ['**/*.test.js'], proxies: { '/spec/': '/base/spec/', }, @@ -99,7 +100,7 @@ module.exports = function (karma) { use: { loader: path.join( __dirname, - '../../examples/webpack/worker-loader.js' + '../../examples/webpack/worker-loader.cjs' ), }, include: [path.join(__dirname, '../../src/ol/worker')], diff --git a/test/rendering/test.js b/test/rendering/test.js index 2eba5909b7..c4b11528b5 100755 --- a/test/rendering/test.js +++ b/test/rendering/test.js @@ -1,18 +1,24 @@ #! /usr/bin/env node -const puppeteer = require('puppeteer'); -const webpack = require('webpack'); -const config = require('./webpack.config'); -const webpackMiddleware = require('webpack-dev-middleware'); -const express = require('express'); -const path = require('path'); -const png = require('pngjs'); -const fs = require('fs'); -const fse = require('fs-extra'); -const pixelmatch = require('pixelmatch'); -const yargs = require('yargs'); -const log = require('loglevelnext'); -const globby = require('globby'); -const serveStatic = require('serve-static'); +import config from './webpack.config.js'; +import esMain from 'es-main'; +import express from 'express'; +import fs from 'fs'; +import fse from 'fs-extra'; +import globby from 'globby'; +import log from 'loglevelnext'; +import path from 'path'; +import pixelmatch from 'pixelmatch'; +import png from 'pngjs'; +import puppeteer from 'puppeteer'; +import serveStatic from 'serve-static'; +import webpack from 'webpack'; +import webpackMiddleware from 'webpack-dev-middleware'; +import yargs from 'yargs'; +import {dirname} from 'path'; +import {fileURLToPath} from 'url'; +import {hideBin} from 'yargs/helpers'; + +const baseDir = dirname(fileURLToPath(import.meta.url)); const compiler = webpack(Object.assign({mode: 'development'}, config)); @@ -20,11 +26,11 @@ function getHref(entry) { return path.dirname(entry).slice(1) + '/'; } -const staticHandler = serveStatic(__dirname); +const staticHandler = serveStatic(baseDir); -const defaultHandler = serveStatic(path.join(__dirname, 'default')); +const defaultHandler = serveStatic(path.join(baseDir, 'default')); -const srcHandler = serveStatic(path.join(__dirname, '..', '..', 'src')); +const srcHandler = serveStatic(path.join(baseDir, '..', '..', 'src')); function indexHandler(req, res) { const items = []; @@ -91,15 +97,15 @@ function serve(options) { } function getActualScreenshotPath(entry) { - return path.join(__dirname, path.dirname(entry), 'actual.png'); + return path.join(baseDir, path.dirname(entry), 'actual.png'); } function getExpectedScreenshotPath(entry) { - return path.join(__dirname, path.dirname(entry), 'expected.png'); + return path.join(baseDir, path.dirname(entry), 'expected.png'); } function getPassFilePath(entry) { - return path.join(__dirname, path.dirname(entry), 'pass'); + return path.join(baseDir, path.dirname(entry), 'pass'); } function parsePNG(filepath) { @@ -284,7 +290,7 @@ async function getLatest(patterns) { async function getOutdated(entries, options) { const libTime = await getLatest( - path.join(__dirname, '..', 'src', 'ol', '**', '*') + path.join(baseDir, '..', 'src', 'ol', '**', '*') ); options.log.debug('library time', libTime); const outdated = []; @@ -298,7 +304,7 @@ async function getOutdated(entries, options) { } const caseTime = await getLatest( - path.join(__dirname, path.dirname(entry), '**', '*') + path.join(baseDir, path.dirname(entry), '**', '*') ); options.log.debug('case time', entry, caseTime); if (passTime < caseTime) { @@ -337,8 +343,8 @@ function sleep(ms) { }); } -if (require.main === module) { - const options = yargs +if (esMain(import.meta)) { + const options = yargs(hideBin(process.argv)) .option('fix', { describe: 'Accept all screenshots as accepted', type: 'boolean', diff --git a/test/rendering/webpack.config.js b/test/rendering/webpack.config.js index f1ddde6f7c..278434bd45 100644 --- a/test/rendering/webpack.config.js +++ b/test/rendering/webpack.config.js @@ -1,7 +1,10 @@ -const fs = require('fs'); -const path = require('path'); +import fs from 'fs'; +import path, {dirname} from 'path'; +import {fileURLToPath} from 'url'; -const cases = path.join(__dirname, 'cases'); +const baseDir = dirname(fileURLToPath(import.meta.url)); + +const cases = path.join(baseDir, 'cases'); const caseDirs = fs.readdirSync(cases).filter((name) => { let exists = true; @@ -18,8 +21,8 @@ caseDirs.forEach((c) => { entry[`cases/${c}/main`] = `./cases/${c}/main.js`; }); -module.exports = { - context: __dirname, +export default { + context: baseDir, target: 'web', entry: entry, devtool: 'source-map', @@ -30,18 +33,18 @@ module.exports = { test: /\.js$/, use: { loader: path.join( - __dirname, - '../../examples/webpack/worker-loader.js' + baseDir, + '../../examples/webpack/worker-loader.cjs' ), }, - include: [path.join(__dirname, '../../src/ol/worker')], + include: [path.join(baseDir, '../../src/ol/worker')], }, ], }, resolve: { alias: { // ol-mapbox-style imports ol/style/Style etc - ol: path.join(__dirname, '..', '..', 'src', 'ol'), + ol: path.join(baseDir, '..', '..', 'src', 'ol'), }, }, };