From af38a64f5c8034978e50d927910280728a67ac7c Mon Sep 17 00:00:00 2001 From: Pavel Mineev Date: Mon, 13 Apr 2020 14:18:29 +0300 Subject: [PATCH 1/5] Frontent infrastructure updates * rename and combine npm scripts * move to checkout@v2 in actions * change dev docs * move liststaged config to package.json because it easier to understand what husky doing --- .github/workflows/ci-test-frontend.yml | 10 +-- Dockerfile | 2 +- README.md | 17 +++-- docs/translation.md | 4 +- frontend/.lintstagedrc.js | 5 -- frontend/.prettierignore | 1 + frontend/Readme.md | 16 ++--- frontend/package-lock.json | 55 ++++++++++++++- frontend/package.json | 95 ++++++++++++++++---------- 9 files changed, 139 insertions(+), 66 deletions(-) delete mode 100644 frontend/.lintstagedrc.js diff --git a/.github/workflows/ci-test-frontend.yml b/.github/workflows/ci-test-frontend.yml index f3aaadcb..a872cb17 100644 --- a/.github/workflows/ci-test-frontend.yml +++ b/.github/workflows/ci-test-frontend.yml @@ -17,18 +17,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - uses: actions/setup-node@v1 - run: npm ci working-directory: ./frontend - - run: npx run-p check lint lint:style test - working-directory: ./frontend - - - run: npm run size - working-directory: ./frontend - - - run: npm run check:translation + - run: npx run-p check lint working-directory: ./frontend diff --git a/Dockerfile b/Dockerfile index fff42efe..efe5d833 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,7 +51,7 @@ ARG NODE_ENV=production COPY --from=build-frontend-deps /srv/frontend/node_modules /srv/frontend/node_modules ADD frontend /srv/frontend RUN cd /srv/frontend && \ - if [ -z "$SKIP_FRONTEND_TEST" ] ; then npx run-p check lint lint:style test build ; \ + if [ -z "$SKIP_FRONTEND_TEST" ] ; then npx run-p lint test check; \ else echo "skip frontend tests and lint" ; npm run build ; fi && \ rm -rf ./node_modules diff --git a/README.md b/README.md index 8415016b..6f1433c6 100644 --- a/README.md +++ b/README.md @@ -587,6 +587,10 @@ It stars backend service with embedded bolt store on port `8080` with basic auth ### Frontend development +#### Developer guide + +Frontend guide can be found here: [./frontend/Readme.md](./frontend/Readme.md) + #### Build You should have at least 2GB RAM or swap enabled for building @@ -597,7 +601,7 @@ You should have at least 2GB RAM or swap enabled for building * result files will be saved in `./frontend/public`. **Note** Running `npm install` will set up precommit hooks into your git repository. -It used to reformat your frontend code using `prettier` and lint with `eslint` before every commit. +It used to reformat your frontend code using `prettier` and lint with `eslint` and `stylelint` before every commit. #### Devserver @@ -612,12 +616,17 @@ You can attach to locally running backend by providing `REMARK_URL` environment npx cross-env REMARK_URL=http://127.0.0.1:8080 npm start ``` +The best way for start local developer enviroment: +```sh +cp compose-dev-frontend.yml compose-private-frontend.yml +docker-compose -f compose-private-frontend.yml up --build +cd frontend +npm run dev +``` + Developer build running by `webpack-dev-server` supports devtools for [React](https://github.com/facebook/react-devtools) and [Redux](https://github.com/zalmoxisus/redux-devtools-extension). -#### Frontend guide - -Frontend guide can be found here: [./frontend/Readme.md](./frontend/Readme.md) ## API diff --git a/docs/translation.md b/docs/translation.md index 0b5af48a..5c7834bf 100644 --- a/docs/translation.md +++ b/docs/translation.md @@ -28,7 +28,7 @@ pull the latest changes from the upstream master branch. It could be done like t 1. add new locale with [two-letter code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) of the language you want to make the translation into to list in [frontend/tasks/supportedLocales.json](https://github.com/umputun/remark42/blob/master/frontend/tasks/supportedLocales.json) -1. run `npm run generate-langs` in `frontend` folder +1. run `npm run translation:generate` in `frontend` folder 1. translate all values in the newly created json file in [frontend/app/locales/](https://github.com/umputun/remark42/blob/master/frontend/app/locales/) 1. commit all changes above in your fork @@ -46,4 +46,4 @@ of the language you want to make the translation into to list in and make sure that your translation looks as you expect it to look 1. make a screenshot from [http://127.0.0.1:8080](http://127.0.0.1:8080) with your translation in place 1. after all previous steps are done, create a [Pull Request](https://github.com/umputun/remark42/pulls) to umputun/remark42 -repo with your changes, attaching a screenshot or two from your local test instance to it \ No newline at end of file +repo with your changes, attaching a screenshot or two from your local test instance to it diff --git a/frontend/.lintstagedrc.js b/frontend/.lintstagedrc.js deleted file mode 100644 index 87611c65..00000000 --- a/frontend/.lintstagedrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - './**/*.{ts,tsx,js,jsx}': [`eslint --fix --max-warnings=0`, `git add`], - './**/*.{scss,pcss,css}': ['prettier --write', 'stylelint', 'git add'], - './iframe.html': ['prettier --write', 'stylelint', 'git add'], -}; diff --git a/frontend/.prettierignore b/frontend/.prettierignore index 3c3629e6..36170a7e 100644 --- a/frontend/.prettierignore +++ b/frontend/.prettierignore @@ -1 +1,2 @@ node_modules +public diff --git a/frontend/Readme.md b/frontend/Readme.md index e2cda451..dd236123 100644 --- a/frontend/Readme.md +++ b/frontend/Readme.md @@ -3,22 +3,22 @@ ### Code Style - project uses typescript to statically analyze code -- project uses `eslint` to check frontend code. You can manually run via `npm run lint`. +- project uses `eslint` and `stylelint` to check frontend code. You can manually run via `npm run lint`. - git hooks (via husky) installed automatically on `npm install` and check and try to fix code style if possible, otherwise commit will be rejected -- if you want IDE integration, you need `eslint` plugin to be installed. +- if you want IDE integration, you need `eslint` and `stylelint` plugin to be installed. ### CSS Styles - - although styles have `scss` extension, it is actually pack of post-css plugins, so syntax differs, for example in `calc` function. -- component styles use BEM notation (at least it should): `block__element_modifier`. Also there are `mix` classes: `block_modifier`. -- component base style resides in the component's root directory with name of component converted to kebab-case. For example `ListComments` style is located in `./app/components/list-comments/list-comments/scss` -- component's element style resides in its own subdirectory, with name consisting of full elements selector, for example `ListComments` `item` element is placed in `__item` directory under name `./list-comments__item.scss` -- each style should be `require`d in `index.ts` of component's root directory +- now we are migrating to css-modules and this is recomended way to stylization. A file with styles should be named like `component.module.css` +- old component styles use BEM notation (at least it should): `block__element_modifier`. Also there are `mix` classes: `block_modifier`. +- new way to naming CSS selectors is camel-case like `blockElemenModifier` and use `classnames` to combine it +- component base style resides in the component's root directory with name of component converted to kebab-case. For example `ListComments` style is located in `./app/components/list-comments/list-component.tsx` +- any other files should be named also in kebab-case. For example `./app/utils/get-param.ts` ### Imports - imports for typescript, javascript files should be without extension: `./index`, not `./index.ts` -- if file resides in same directory or in subdirectory import should be relative: `./types/something` +- if file resides in the same directory or in subdirectory import should be relative: `./types/something` - otherwise it should start from `@app` namespace: `@app/common/store` which mapped to `/app/common/store.ts` in webpack, tsconfig and jest ### Testing diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e6db45d4..30871964 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -5840,6 +5840,58 @@ "sha.js": "^2.4.8" } }, + "cross-env": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz", + "integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "cross-fetch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.4.tgz", @@ -22599,8 +22651,7 @@ "whatwg-fetch": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", - "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==", - "dev": true + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" }, "whatwg-mimetype": { "version": "2.3.0", diff --git a/frontend/package.json b/frontend/package.json index e25f814e..fe38b765 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,25 +3,46 @@ "version": "0.1.0", "license": "MIT", "scripts": { - "build": "webpack --mode production && es-check es5 './public/*.js'", + "build": "webpack --mode production", "start": "webpack-dev-server --mode development", - "check": "tsc -p tsconfig.typecheck.json --noEmit --skipLibCheck", - "check:translation": "npm run extract-messages && node ./tasks/checkTranslation.js", - "lint": "eslint --max-warnings=0 --ext=.ts,.tsx,.js,.jsx .", - "lint:style": "stylelint '**/*.scss' '**/*.pcss' '**/*.css' 'iframe.html'", + "dev": "cross-env REMARK_URL=http://127.0.0.1:8080 npm start", "test": "jest", + "check": "NODE_ENV=production npm run build && run-p check:*", + "check:types": "tsc -p tsconfig.typecheck.json --noEmit --skipLibCheck", + "check:translation": "run-s translation:extract translation:check", + "check:size": "size-limit", + "check:es": "es-check es5 './public/*.js'", + "lint": "run-p lint:*", + "lint:eslint": "eslint --max-warnings=0 --ext=.ts,.tsx,.js,.jsx .", + "lint:stylelint": "stylelint '**/*.scss' '**/*.pcss' '**/*.css' 'iframe.html'", "test:coverage": "jest --coverage", "prettier": "prettier --write './**/*.{js,jsx,ts,tsx,scss}'", - "extract-messages": "formatjs extract --out-file=./extracted-messages/messages.json './app/**/*.{js,jsx,ts,tsx}'", - "generate-langs": "npm run extract-messages && node ./tasks/generateDictionary.js", - "size": "NODE_ENV=production npm run build && size-limit" + "translation:extract": "formatjs extract --out-file=./extracted-messages/messages.json './app/**/*.{js,jsx,ts,tsx}'", + "translation:generate": "node ./tasks/generateDictionary.js", + "translation:check": "node ./tasks/checkTranslation.js" }, - "husky": { - "hooks": { - "pre-commit": "./node_modules/.bin/lint-staged", - "post-commit": "git update-index --again", - "pre-push": "npm run check && npm test" - } + "engines": { + "node": ">=12.11", + "npm": ">=6.13.4" + }, + "dependencies": { + "@github/markdown-toolbar-element": "^1.2.0", + "@github/text-expander-element": "^1.0.2", + "@webcomponents/custom-elements": "^1.4.1", + "bem-react-helper": "^1.1.2", + "classnames": "^2.2.6", + "core-js": "^3.6.5", + "es6-promise": "^4.2.8", + "focus-visible": "^5.1.0", + "intersection-observer": "^0.7.0", + "lodash-es": "^4.17.15", + "node-emoji": "^1.10.0", + "preact": "^10.4.0", + "react-intl": "^3.12.0", + "react-redux": "^7.1.1", + "redux": "^4.0.5", + "redux-thunk": "^2.3.0", + "whatwg-fetch": "^3.0.0" }, "devDependencies": { "@babel/core": "^7.6.4", @@ -51,6 +72,7 @@ "babel-loader": "^8.0.6", "clean-webpack-plugin": "^3.0.0", "copy-webpack-plugin": "^5.1.1", + "cross-env": "^7.0.2", "css-loader": "^3.2.0", "document-register-element": "^1.14.3", "dotenv": "^8.2.0", @@ -100,29 +122,30 @@ "webpack": "^4.41.2", "webpack-bundle-analyzer": "^3.6.1", "webpack-cli": "^3.3.9", - "webpack-dev-server": "^3.9.0", - "whatwg-fetch": "^3.0.0" + "webpack-dev-server": "^3.9.0" }, - "dependencies": { - "@github/markdown-toolbar-element": "^1.2.0", - "@github/text-expander-element": "^1.0.2", - "@webcomponents/custom-elements": "^1.4.1", - "bem-react-helper": "^1.1.2", - "classnames": "^2.2.6", - "core-js": "^3.6.5", - "es6-promise": "^4.2.8", - "focus-visible": "^5.1.0", - "intersection-observer": "^0.7.0", - "lodash-es": "^4.17.15", - "node-emoji": "^1.10.0", - "preact": "^10.4.0", - "react-intl": "^3.12.0", - "react-redux": "^7.1.1", - "redux": "^4.0.5", - "redux-thunk": "^2.3.0" + "husky": { + "hooks": { + "pre-commit": "lint-staged", + "post-commit": "git update-index --again", + "pre-push": "run-s check test" + } }, - "engines": { - "node": ">=12.11", - "npm": ">=6.13.4" + "lint-staged": { + "./**/*.{ts,tsx,js,jsx}": [ + "eslint --fix --max-warnings=0", + "prettier --write", + "git add" + ], + "./**/*.{scss,pcss,css}": [ + "prettier --write", + "stylelint", + "git add" + ], + "./iframe.html": [ + "prettier --write", + "stylelint", + "git add" + ] } } From 7d4b6d22f0f153b5a078c6dbc3764e6cb0b16f51 Mon Sep 17 00:00:00 2001 From: Pavel Mineev Date: Mon, 13 Apr 2020 16:06:03 +0300 Subject: [PATCH 2/5] show only warn and error messages on install without other visual noise --- .github/workflows/ci-test-frontend.yml | 2 +- Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-test-frontend.yml b/.github/workflows/ci-test-frontend.yml index a872cb17..88b2c8f0 100644 --- a/.github/workflows/ci-test-frontend.yml +++ b/.github/workflows/ci-test-frontend.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/setup-node@v1 - - run: npm ci + - run: npm ci --loglevel warn working-directory: ./frontend - run: npx run-p check lint diff --git a/Dockerfile b/Dockerfile index efe5d833..4f2d90dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,7 +40,7 @@ ENV HUSKY_SKIP_INSTALL=true RUN apk add --no-cache --update git ADD frontend/package.json /srv/frontend/package.json ADD frontend/package-lock.json /srv/frontend/package-lock.json -RUN cd /srv/frontend && CI=true npm ci +RUN cd /srv/frontend && CI=true npm ci --loglevel warn FROM node:10.11-alpine as build-frontend From 8d02ad432cbb608b43f2a9cc87f68ce6a414b398 Mon Sep 17 00:00:00 2001 From: Pavel Mineev Date: Mon, 13 Apr 2020 16:10:35 +0300 Subject: [PATCH 3/5] add cross-env for npm run check --- frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index fe38b765..b1b6e901 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,7 +7,7 @@ "start": "webpack-dev-server --mode development", "dev": "cross-env REMARK_URL=http://127.0.0.1:8080 npm start", "test": "jest", - "check": "NODE_ENV=production npm run build && run-p check:*", + "check": "cross-env NODE_ENV=production npm run build && run-p check:*", "check:types": "tsc -p tsconfig.typecheck.json --noEmit --skipLibCheck", "check:translation": "run-s translation:extract translation:check", "check:size": "size-limit", From 51fc0f7a92bc1a1b730dae044242c206d5491698 Mon Sep 17 00:00:00 2001 From: Pavel Mineev Date: Mon, 13 Apr 2020 21:58:01 +0300 Subject: [PATCH 4/5] put all config in separate js files --- frontend/.eslintignore | 1 + frontend/.huskyrc.js | 7 +++++++ frontend/.lintstagedrc.js | 5 +++++ frontend/.prettierrc | 17 ----------------- frontend/.prettierrc.js | 17 +++++++++++++++++ frontend/package.json | 24 ------------------------ 6 files changed, 30 insertions(+), 41 deletions(-) create mode 100644 frontend/.huskyrc.js create mode 100644 frontend/.lintstagedrc.js delete mode 100644 frontend/.prettierrc create mode 100644 frontend/.prettierrc.js diff --git a/frontend/.eslintignore b/frontend/.eslintignore index 2348c2db..524d155a 100644 --- a/frontend/.eslintignore +++ b/frontend/.eslintignore @@ -6,3 +6,4 @@ public !.lintstagedrc.js !.stylelintrc.js !.size-limit.js +!.huskyrc.js diff --git a/frontend/.huskyrc.js b/frontend/.huskyrc.js new file mode 100644 index 00000000..2a0b0c18 --- /dev/null +++ b/frontend/.huskyrc.js @@ -0,0 +1,7 @@ +module.exports = { + hooks: { + 'pre-commit': 'lint-staged', + 'post-commit': 'git update-index --again', + 'pre-push': 'run-s check test', + }, +}; diff --git a/frontend/.lintstagedrc.js b/frontend/.lintstagedrc.js new file mode 100644 index 00000000..dc6e1161 --- /dev/null +++ b/frontend/.lintstagedrc.js @@ -0,0 +1,5 @@ +module.exports = { + './**/*.{ts,tsx,js,jsx}': ['eslint --fix --max-warnings=0', 'prettier --write', 'git add'], + './**/*.{scss,pcss,css}': ['prettier --write', 'stylelint', 'git add'], + './iframe.html': ['prettier --write', 'stylelint', 'git add'], +}; diff --git a/frontend/.prettierrc b/frontend/.prettierrc deleted file mode 100644 index bd27edb1..00000000 --- a/frontend/.prettierrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "printWidth": 120, - "useTabs": false, - "semi": true, - "singleQuote": true, - "trailingComma": "es5", - "bracketSpacing": true, - "arrowParens": "avoid", - "overrides": [ - { - "files": ["*.ejs", "*.html"], - "options": { - "trailingComma": "none" - } - } - ] -} diff --git a/frontend/.prettierrc.js b/frontend/.prettierrc.js new file mode 100644 index 00000000..7f94fc39 --- /dev/null +++ b/frontend/.prettierrc.js @@ -0,0 +1,17 @@ +module.exports = { + printWidth: 120, + useTabs: false, + semi: true, + singleQuote: true, + trailingComma: 'es5', + bracketSpacing: true, + arrowParens: 'avoid', + overrides: [ + { + files: ['*.ejs', '*.html'], + options: { + trailingComma: 'none', + }, + }, + ], +}; diff --git a/frontend/package.json b/frontend/package.json index b1b6e901..e833df3e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -123,29 +123,5 @@ "webpack-bundle-analyzer": "^3.6.1", "webpack-cli": "^3.3.9", "webpack-dev-server": "^3.9.0" - }, - "husky": { - "hooks": { - "pre-commit": "lint-staged", - "post-commit": "git update-index --again", - "pre-push": "run-s check test" - } - }, - "lint-staged": { - "./**/*.{ts,tsx,js,jsx}": [ - "eslint --fix --max-warnings=0", - "prettier --write", - "git add" - ], - "./**/*.{scss,pcss,css}": [ - "prettier --write", - "stylelint", - "git add" - ], - "./iframe.html": [ - "prettier --write", - "stylelint", - "git add" - ] } } From 5e71613d4fe4ead2615412f614ef6142188ad86d Mon Sep 17 00:00:00 2001 From: Pavel Mineev Date: Mon, 13 Apr 2020 22:03:37 +0300 Subject: [PATCH 5/5] add instant commands --- frontend/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index e833df3e..aa9bba7a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,6 +7,7 @@ "start": "webpack-dev-server --mode development", "dev": "cross-env REMARK_URL=http://127.0.0.1:8080 npm start", "test": "jest", + "test:coverage": "jest --coverage", "check": "cross-env NODE_ENV=production npm run build && run-p check:*", "check:types": "tsc -p tsconfig.typecheck.json --noEmit --skipLibCheck", "check:translation": "run-s translation:extract translation:check", @@ -15,7 +16,8 @@ "lint": "run-p lint:*", "lint:eslint": "eslint --max-warnings=0 --ext=.ts,.tsx,.js,.jsx .", "lint:stylelint": "stylelint '**/*.scss' '**/*.pcss' '**/*.css' 'iframe.html'", - "test:coverage": "jest --coverage", + "size": "cross-env NODE_ENV=production run-s build check:size", + "es-check": "cross-env NODE_ENV=production run-s build check:es", "prettier": "prettier --write './**/*.{js,jsx,ts,tsx,scss}'", "translation:extract": "formatjs extract --out-file=./extracted-messages/messages.json './app/**/*.{js,jsx,ts,tsx}'", "translation:generate": "node ./tasks/generateDictionary.js",