diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 00000000..ca48b1ad --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,79 @@ +module.exports = { + root: true, + parserOptions: { + ecmaVersion: 2022, + }, + env: { + es6: true, + browser: true, + mocha: true, + node: true, + }, + rules: { + "block-scoped-var": "error", + curly: ["error", "all"], + "dot-notation": "error", + eqeqeq: "error", + "handle-callback-err": "error", + "no-alert": "error", + "no-catch-shadow": "error", + "no-control-regex": "off", + "no-console": "error", + "no-duplicate-imports": "error", + "no-else-return": "error", + "no-implicit-globals": "error", + "no-restricted-globals": ["error", "event", "fdescribe"], + "no-shadow": "error", + "no-template-curly-in-string": "error", + "no-unsafe-negation": "error", + "no-useless-computed-key": "error", + "no-useless-constructor": "error", + "no-useless-return": "error", + "no-use-before-define": [ + "error", + { + functions: false, + }, + ], + "no-var": "error", + "object-shorthand": [ + "error", + "methods", + { + avoidExplicitReturnArrows: true, + }, + ], + "padding-line-between-statements": [ + "error", + { + blankLine: "always", + prev: ["block", "block-like"], + next: "*", + }, + { + blankLine: "always", + prev: "*", + next: ["block", "block-like"], + }, + ], + "prefer-const": "error", + "prefer-rest-params": "error", + "prefer-spread": "error", + "spaced-comment": ["error", "always"], + strict: "off", + yoda: "error", + "vue/component-tags-order": [ + "error", + { + order: ["template", "style", "script"], + }, + ], + "vue/no-mutating-props": "off", + "vue/no-v-html": "off", + "vue/require-default-prop": "off", + "vue/v-slot-style": ["error", "longform"], + "vue/multi-word-component-names": "off", + }, + plugins: ["vue"], + extends: ["eslint:recommended", "plugin:vue/recommended", "prettier"], +}; diff --git a/.eslintrc.yml b/.eslintrc.yml deleted file mode 100644 index 0c36982a..00000000 --- a/.eslintrc.yml +++ /dev/null @@ -1,80 +0,0 @@ ---- -root: true - -parserOptions: - ecmaVersion: 2022 - -env: - es6: true - browser: true - mocha: true - node: true - -rules: - block-scoped-var: error - curly: [error, all] - dot-notation: error - eqeqeq: error - handle-callback-err: error - no-alert: error - no-catch-shadow: error - no-control-regex: off - no-console: error - no-duplicate-imports: error - no-else-return: error - no-implicit-globals: error - no-restricted-globals: - - error - - event - - fdescribe - no-shadow: error - no-template-curly-in-string: error - no-unsafe-negation: error - no-useless-computed-key: error - no-useless-constructor: error - no-useless-return: error - no-use-before-define: - - error - - functions: false - no-var: error - object-shorthand: - - error - - methods - - avoidExplicitReturnArrows: true - padding-line-between-statements: - - error - - blankLine: always - prev: - - block - - block-like - next: "*" - - blankLine: always - prev: "*" - next: - - block - - block-like - prefer-const: error - prefer-rest-params: error - prefer-spread: error - spaced-comment: [error, always] - strict: off - yoda: error - vue/component-tags-order: - - error - - order: - - template - - style - - script - vue/no-mutating-props: off - vue/no-v-html: off - vue/require-default-prop: off - vue/v-slot-style: [error, longform] - vue/multi-word-component-names: off - -plugins: - - vue - -extends: - - eslint:recommended - - plugin:vue/recommended - - prettier diff --git a/.prettierrc.yml b/.prettierrc.yml deleted file mode 100644 index 4bad5750..00000000 --- a/.prettierrc.yml +++ /dev/null @@ -1,8 +0,0 @@ -arrowParens: always -bracketSpacing: false -printWidth: 100 -trailingComma: "es5" -overrides: - - files: "*.webmanifest" - options: - parser: json diff --git a/.stylelintrc.yml b/.stylelintrc.yml deleted file mode 100644 index 3c6ab11e..00000000 --- a/.stylelintrc.yml +++ /dev/null @@ -1,19 +0,0 @@ -extends: stylelint-config-standard - -rules: - indentation: tab - # complains about FontAwesome - font-family-no-missing-generic-family-keyword: - # needs a lot of refactoring to be enabled - no-descending-specificity: - - # we have autoprefixer - at-rule-no-vendor-prefix: true - media-feature-name-no-vendor-prefix: true - property-no-vendor-prefix: true - selector-no-vendor-prefix: true - value-no-vendor-prefix: true - - # renaming would break existing themes - selector-class-pattern: null - selector-id-pattern: null diff --git a/babel.config.cjs b/babel.config.cjs new file mode 100644 index 00000000..059d55ab --- /dev/null +++ b/babel.config.cjs @@ -0,0 +1,3 @@ +module.exports = { + presets: [["@babel/env"]], +}; diff --git a/package.json b/package.json index fd18ab16..ce58b950 100644 --- a/package.json +++ b/package.json @@ -16,13 +16,13 @@ "coverage": "run-s test:* && nyc --nycrc-path=test/.nycrc-report.json report", "dev": "node index start --dev", "format:prettier": "prettier --write \"**/*.*\"", - "lint:check-eslint": "eslint-config-prettier .eslintrc.yml", + "lint:check-eslint": "eslint-config-prettier .eslintrc.cjs", "lint:eslint": "eslint . --ext .js,.vue --report-unused-disable-directives --color", "lint:prettier": "prettier --list-different \"**/*.*\"", "lint:stylelint": "stylelint --color \"client/**/*.css\"", "start": "node index start", "test": "run-p --aggregate-output --continue-on-error lint:* test:*", - "test:mocha": "webpack --config webpack.config-test.js && nyc --nycrc-path=test/.nycrc-mocha.json mocha --colors --config=test/.mocharc.yml", + "test:mocha": "webpack --mode=development && nyc --nycrc-path=test/.nycrc-mocha.json mocha --colors --config=test/.mocharc.yml", "watch": "webpack --watch" }, "keywords": [ diff --git a/prettier.config.cjs b/prettier.config.cjs new file mode 100644 index 00000000..374fa93e --- /dev/null +++ b/prettier.config.cjs @@ -0,0 +1,14 @@ +module.exports = { + arrowParens: "always", + bracketSpacing: false, + printWidth: 100, + trailingComma: "es5", + overrides: [ + { + files: "*.webmanifest", + options: { + parser: "json", + }, + }, + ], +}; diff --git a/stylelint.config.cjs b/stylelint.config.cjs new file mode 100644 index 00000000..560321ad --- /dev/null +++ b/stylelint.config.cjs @@ -0,0 +1,15 @@ +module.exports = { + extends: "stylelint-config-standard", + rules: { + indentation: "tab", + "font-family-no-missing-generic-family-keyword": null, + "no-descending-specificity": null, + "at-rule-no-vendor-prefix": true, + "media-feature-name-no-vendor-prefix": true, + "property-no-vendor-prefix": true, + "selector-no-vendor-prefix": true, + "value-no-vendor-prefix": true, + "selector-class-pattern": null, + "selector-id-pattern": null, + }, +}; diff --git a/webpack.config-test.js b/webpack.config-test.js deleted file mode 100644 index b6154133..00000000 --- a/webpack.config-test.js +++ /dev/null @@ -1,49 +0,0 @@ -"use strict"; - -const webpack = require("webpack"); -const fs = require("fs"); -const path = require("path"); -const VueLoaderPlugin = require("vue-loader/lib/plugin"); -const config = require("./webpack.config.js"); - -const testFile = path.resolve(__dirname, "test/public/testclient.js"); - -if (fs.existsSync(testFile)) { - fs.unlinkSync(testFile); -} - -config.target = "node"; -config.devtool = "eval"; -config.stats = "errors-only"; -config.output.path = path.resolve(__dirname, "test/public"); -config.entry = { - "testclient.js": [path.resolve(__dirname, "test/client/index.js")], -}; - -// Add the istanbul plugin to babel-loader options -for (const rule of config.module.rules) { - if (rule.use.loader === "babel-loader") { - rule.use.options.plugins = ["istanbul"]; - } -} - -// `optimization.splitChunks` is incompatible with a `target` of `node`. See: -// - https://github.com/zinserjan/mocha-webpack/issues/84 -// - https://github.com/webpack/webpack/issues/6727#issuecomment-372589122 -config.optimization.splitChunks = false; - -// Disable plugins like copy files, it is not required -config.plugins = [ - new VueLoaderPlugin(), - - // Client tests that require Vue may end up requireing socket.io - new webpack.NormalModuleReplacementPlugin( - /js(\/|\\)socket\.js/, - path.resolve(__dirname, "scripts/noop.js") - ), - - // "Fixes" Critical dependency: the request of a dependency is an expression - new webpack.ContextReplacementPlugin(/vue-server-renderer$/), -]; - -module.exports = config; diff --git a/webpack.config.js b/webpack.config.js index 0fd09009..86357f88 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,11 +1,13 @@ "use strict"; const webpack = require("webpack"); +const fs = require("fs"); const path = require("path"); const CopyPlugin = require("copy-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const VueLoaderPlugin = require("vue-loader/lib/plugin"); const Helper = require("./src/helper.js"); +const babelConfig = require("./babel.config.cjs"); const isProduction = process.env.NODE_ENV === "production"; const config = { @@ -65,9 +67,7 @@ const config = { include: [path.resolve(__dirname, "client")], use: { loader: "babel-loader", - options: { - presets: [["@babel/env"]], - }, + options: babelConfig, }, }, ], @@ -142,4 +142,52 @@ const config = { ], }; -module.exports = config; +module.exports = (env, argv) => { + if (argv.mode === "development") { + const testFile = path.resolve(__dirname, "test/public/testclient.js"); + + if (fs.existsSync(testFile)) { + fs.unlinkSync(testFile); + } + + config.target = "node"; + config.devtool = "eval"; + config.stats = "errors-only"; + config.output.path = path.resolve(__dirname, "test/public"); + config.entry = { + "testclient.js": [path.resolve(__dirname, "test/client/index.js")], + }; + + // Add the istanbul plugin to babel-loader options + for (const rule of config.module.rules) { + if (rule.use.loader === "babel-loader") { + rule.use.options.plugins = ["istanbul"]; + } + } + + // `optimization.splitChunks` is incompatible with a `target` of `node`. See: + // - https://github.com/zinserjan/mocha-webpack/issues/84 + // - https://github.com/webpack/webpack/issues/6727#issuecomment-372589122 + config.optimization.splitChunks = false; + + // Disable plugins like copy files, it is not required + config.plugins = [ + new VueLoaderPlugin(), + + // Client tests that require Vue may end up requireing socket.io + new webpack.NormalModuleReplacementPlugin( + /js(\/|\\)socket\.js/, + path.resolve(__dirname, "scripts/noop.js") + ), + + // "Fixes" Critical dependency: the request of a dependency is an expression + new webpack.ContextReplacementPlugin(/vue-server-renderer$/), + ]; + } + + if (argv.mode === "production") { + // ... + } + + return config; +};