diff --git a/.babelrc b/.babelrc index d67c0cfda9..fda3879d0f 100644 --- a/.babelrc +++ b/.babelrc @@ -1,37 +1,3 @@ { - "presets": ["flow", "react", "env", "stage-0"], - "plugins": [ - "transform-runtime", - "add-module-exports", - "transform-decorators-legacy", - "transform-class-properties", - "add-react-displayname", - ["babel-plugin-root-import", { - "rootPathSuffix": "src" - }] - ], - "env": { - "development": { - "plugins": [ - "typecheck", - [ - "react-transform", - { - "transforms": [ - { - "transform": "react-transform-catch-errors", - "imports": ["react", "redbox-react"] - } - ] - } - ], - [ - "react-intl", - { - "messagesDir": "./dist/messages/" - } - ] - ] - } - } + "presets": ["./babel"] } diff --git a/.eslintrc b/.eslintrc index 95e90b647a..71eb0838a5 100644 --- a/.eslintrc +++ b/.eslintrc @@ -27,7 +27,9 @@ ], "jsx-a11y/anchor-is-valid": [ "error", { "components": [ "Link" ], "specialLink": [ "to" ] } ], "import/prefer-default-export": "off", - "react/prefer-stateless-function": 0 + "react/prefer-stateless-function": 0, + "import/no-unresolved": 0, + "import/extensions": 0 }, "settings": { "import/resolver": { diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index 43ec549f6f..0000000000 --- a/.flowconfig +++ /dev/null @@ -1,12 +0,0 @@ -[ignore] -.*/api/.* -.*/node_modules/draft-js/.* -.*/node_modules/jss/.* -.*/node_modules/findup/.* -.*/node_modules/immutable/.* - -[include] - -[libs] - -[options] diff --git a/.gitignore b/.gitignore index 9cb321ce38..170ba11d8a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ dist junit.xml eslint.xml yarn-error.log +build # Other .DS_Store @@ -30,6 +31,8 @@ api/.Python api/include api/lib api/pip-selfcheck.json +/bin +/lib # Tests /tests/bin @@ -42,3 +45,4 @@ log.html output.xml report.html selenium-screenshot-*.png +/selenium/ diff --git a/.travis.yml b/.travis.yml index 8e1a647c8a..1b1a68d617 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,76 +1,76 @@ language: python matrix: include: - - name: "Plone Tests" - python: 2.7.14 - env: TEST_SUITE=plone - - name: "Guillotina Tests" - python: 3.7 - dist: xenial - env: TEST_SUITE=guillotina - - name: "Unit Tests" - env: TEST_SUITE=unit + - name: 'Plone Tests' + python: 2.7.14 + env: TEST_SUITE=plone + - name: 'Guillotina Tests' + python: 3.7 + dist: xenial + env: TEST_SUITE=guillotina + - name: 'Unit Tests' + env: TEST_SUITE=unit cache: pip: true directories: - - node_modules + - node_modules sudo: required services: - docker addons: apt: sources: - - google-chrome + - google-chrome packages: - - google-chrome-stable + - google-chrome-stable before_install: -- nvm install 8.11.3; -- docker build -t plone/plone-react:testing . -- if [ "$TEST_SUITE" != "unit" ]; then - mkdir webdriver; - wget https://github.com/mozilla/geckodriver/releases/download/v0.20.0/geckodriver-v0.20.0-linux64.tar.gz; - tar -xzf geckodriver-v0.20.0-linux64.tar.gz -C webdriver; - wget https://chromedriver.storage.googleapis.com/2.42/chromedriver_linux64.zip; - unzip chromedriver_linux64.zip -d webdriver; - export PATH=$PATH:$(pwd)/webdriver; - npm install -g surge; - fi + - nvm install 8.11.3; + - docker build -t plone/plone-react:testing . + - if [ "$TEST_SUITE" != "unit" ]; then + mkdir webdriver; + wget https://github.com/mozilla/geckodriver/releases/download/v0.20.0/geckodriver-v0.20.0-linux64.tar.gz; + tar -xzf geckodriver-v0.20.0-linux64.tar.gz -C webdriver; + wget https://chromedriver.storage.googleapis.com/2.40/chromedriver_linux64.zip; + unzip chromedriver_linux64.zip -d webdriver; + export PATH=$PATH:$(pwd)/webdriver; + npm install -g surge; + fi install: -- if [ "$TEST_SUITE" == "plone" ]; then - virtualenv env --python=$(which python) --no-site-packages; - env/bin/pip install zc.recipe.egg==2.0.4 --no-cache-dir; - env/bin/pip install -r api/docker/requirements.txt; - env/bin/pip install -U https://github.com/zopefoundation/z3c.autoinclude/archive/pip.tar.gz#egg=z3c.autoinclude; - fi -- pip install -r test-requirements.txt; -- yarn -- yarn build + - if [ "$TEST_SUITE" == "plone" ]; then + virtualenv env --python=$(which python) --no-site-packages; + env/bin/pip install zc.recipe.egg==2.0.4 --no-cache-dir; + env/bin/pip install -r api/docker/requirements.txt; + env/bin/pip install -U https://github.com/zopefoundation/z3c.autoinclude/archive/pip.tar.gz#egg=z3c.autoinclude; + fi + - pip install -r test-requirements.txt; + - yarn + - yarn build before_script: -- "export DISPLAY=:99.0" -- "sh -e /etc/init.d/xvfb start" -- sleep 3 + - 'export DISPLAY=:99.0' + - 'sh -e /etc/init.d/xvfb start' + - sleep 3 script: -- if [ "$TEST_SUITE" == "unit" ]; then - docker run --name coverage_front -e TRAVIS_JOB_ID="$TRAVIS_JOB_ID" -e TRAVIS_BRANCH="$TRAVIS_BRANCH" plone/plone-react:testing -- yarn test; - docker cp coverage_front:/opt/app/coverage/lcov.info .; - cat lcov.info | ./node_modules/coveralls/bin/coveralls.js; - fi -- if [ "$TEST_SUITE" == "guillotina" ]; then - PYTHONPATH=$(pwd)/tests pybot -v BROWSER:headlesschrome -v API:Guillotina tests; - fi -- if [ "$TEST_SUITE" == "plone" ]; then - PYTHONPATH=$(pwd)/tests env/bin/pybot -v BROWSER:headlesschrome -v API:Plone tests; - fi + - if [ "$TEST_SUITE" == "unit" ]; then + docker run --name coverage_front -e TRAVIS_JOB_ID="$TRAVIS_JOB_ID" -e TRAVIS_BRANCH="$TRAVIS_BRANCH" plone/plone-react:testing -- yarn test --coverage; + docker cp coverage_front:/opt/app/coverage/lcov.info .; + cat lcov.info | ./node_modules/coveralls/bin/coveralls.js; + fi +# - if [ "$TEST_SUITE" == "guillotina" ]; then +# PYTHONPATH=$(pwd)/tests pybot -v BROWSER:headlesschrome -v API:Guillotina tests; +# fi +# - if [ "$TEST_SUITE" == "plone" ]; then +# PYTHONPATH=$(pwd)/tests env/bin/pybot -v BROWSER:headlesschrome -v API:Plone tests; +# fi after_script: -- mkdir robot-results -- mv log.html output.xml report.html selenium-screenshot-*.png robot-results -- ls -al robot-results -- surge robot-results plone-react.surge.sh + - mkdir robot-results + - mv log.html output.xml report.html selenium-screenshot-*.png robot-results + - ls -al robot-results + - surge robot-results plone-react.surge.sh after_success: -- if [ "$TEST_SUITE" == "guillotina" ]; then - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; - docker tag plone/plone-react:testing plone/plone-react:$TRAVIS_BRANCH.$TRAVIS_COMMIT; - docker push plone/plone-react:$TRAVIS_BRANCH.$TRAVIS_COMMIT; - docker tag plone/plone-react:testing plone/plone-react:$TRAVIS_BRANCH.latest; - docker push plone/plone-react:$TRAVIS_BRANCH.latest; - fi \ No newline at end of file + - if [ "$TEST_SUITE" == "guillotina" ]; then + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; + docker tag plone/plone-react:testing plone/plone-react:$TRAVIS_BRANCH.$TRAVIS_COMMIT; + docker push plone/plone-react:$TRAVIS_BRANCH.$TRAVIS_COMMIT; + docker tag plone/plone-react:testing plone/plone-react:$TRAVIS_BRANCH.latest; + docker push plone/plone-react:$TRAVIS_BRANCH.latest; + fi diff --git a/CHANGELOG.md b/CHANGELOG.md index fd80096697..b574a4b012 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,31 @@ # Change Log -## 0.8.0 (unreleased) +## 0.8.3 (2018-08-03) + +### Changes + +- Fix i18n script for dependency @robgietema + +## 0.8.2 (2018-08-03) + +### Changes + +- Move all dev dependencies to dependencies @robgietema + +## 0.8.1 (2018-08-03) + +### Changes + +- Fix compiling when used as a library @robgietema + +## 0.8.0 (2018-08-03) ### Added +- Move the webpack config to Razzle @sneridagh @robgietema - Upgrade React to 16.5 @tisto - Upgrade React to 16.4.2 to fix a server-side vulnerability @tisto +- Support for base url @bloodbare ### Changes diff --git a/Dockerfile b/Dockerfile index 5fadece30f..5d60622b76 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM node:8.11.4-slim -RUN apt-get update -y +RUN apt-get update -y RUN apt-get install -y libpng12-dev WORKDIR /opt/app/ @@ -16,7 +16,7 @@ RUN yarn build ENV API_PATH http://api/db/web ENV PUBLIC_URL / -EXPOSE 4300 +EXPOSE 3000 ENTRYPOINT ["/opt/app/entrypoint.sh"] -CMD yarn run:prod:server \ No newline at end of file +CMD yarn start:prod diff --git a/Makefile b/Makefile index 75b98a3663..90533192ee 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ dist: yarn build start: dist - yarn start + yarn start:prod start-api-docker: docker-compose -f api/docker-compose.yml up @@ -20,7 +20,7 @@ test-acceptance-start-backend: docker-compose -f api/docker-compose.yml up test-acceptance-start-frontend: - yarn && yarn build && API_PATH=http://localhost:55001/plone yarn start + yarn && yarn build && API_PATH=http://localhost:55001/plone yarn start:prod test-acceptance-build: api/bin/pip install -r api/requirements-robot-framework.txt diff --git a/README.md b/README.md index e788052dd2..fdb5650d0a 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ ### Prerequisites -* [Node.js==8.11.3](https://nodejs.org/) -* [Python==2.7.x](https://python.org/) +- [Node.js==8.11.3](https://nodejs.org/) +- [Python==2.7.x](https://python.org/) ### Install dependencies @@ -35,11 +35,11 @@ ### Run frontend - $ yarn dev + $ yarn start ### Browsing -Go to [http://localhost:4300](http://localhost:4300) in your browser. +Go to [http://localhost:3000](http://localhost:3000) in your browser. ### Testing @@ -52,7 +52,7 @@ Go to [http://localhost:4300](http://localhost:4300) in your browser. Alternatively individual acceptances test case files can be run with a pure Robot Framework virtual environment, assuming that backend and frontend is running $ docker-compose -f api/docker-compose.yml up - $ yarn && yarn build && API_PATH=http://localhost:55001/plone yarn start + $ yarn && yarn build && API_PATH=http://localhost:55001/plone yarn start:prod $ virtualenv robotenv --no-site-packages $ robotenv/bin/pip install robotframework robotframework-seleniumlibrary robotframework-webpack @@ -138,7 +138,6 @@ More Precommit hooks can be found [here](https://prettier.io/docs/en/precommit.h MIT License. Copyrights hold the Plone Foundation. See [LICENSE.md](LICENSE.md) for details. - ### Running Guillotina Tests First, start up Guillotina: @@ -149,7 +148,6 @@ docker-compose -f g-api/docker-compose.yml up -d Then, run the tests: - ``` PYTHONPATH=$(pwd)/tests_guillotina env/bin/pybot -v BROWSER:headlesschrome tests_guillotina; ``` diff --git a/api/buildout.cfg b/api/buildout.cfg index 947458bb14..dfbdfcd824 100644 --- a/api/buildout.cfg +++ b/api/buildout.cfg @@ -25,7 +25,7 @@ zcml-additional = \n" "Language-Team: Plone i18n \n" "MIME-Version: 1.0\n" @@ -120,6 +120,7 @@ msgid "By default, permissions from the container of this item are inherited. If msgstr "" #: components/manage/Add/Add +#: components/manage/Contents/ContentsToolbar #: components/manage/Contents/ContentsUploadModal #: components/manage/Controlpanels/UsersControlpanel #: components/manage/Delete/Delete @@ -581,6 +582,7 @@ msgid "New password" msgstr "" #: components/manage/Widgets/ArrayWidget +#: components/manage/Widgets/ReferenceWidget # defaultMessage: No results found. msgid "No results found." msgstr "" diff --git a/package.json b/package.json index 8fd35a63cb..aa9edc61b3 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ } ], "license": "MIT", - "version": "0.7.0", + "version": "0.8.3", "repository": { "type": "git", "url": "git@github.com:plone/plone-react.git" @@ -24,48 +24,14 @@ "react", "mosaic" ], - "main": "src/server.jsx", "scripts": { - "test:start": "DEBUG=plone-react:* npm-run-all -ln prestart start & npm-run-all -ln wait-for-frontend", - "start": "NODE_ENV=production npm-run-all prod", - "dev": "NODE_ENV=development npm-run-all dev:build", - "dev:build": "npm-run-all -ln clear:dist prepare:dev:build i18n:build development", - "development": "npm-run-all -ln --parallel build:dev:client build:dev:server run:dev:server", - "prepare:dev:build": "universal-webpack --settings ./webpack/universal-webpack-settings.js prepare", - "build:dev:client": "better-npm-run run_dev_client", - "build:dev:server": "better-npm-run build_dev_server", - "run:dev:server": "better-npm-run run_dev_server", - "clear:dist": "rm -rf dist", - "build": "npm-run-all clear:dist prod:build:client i18n:build prod:build:server", - "build:analyse": "npm run build && node_modules/webpack-bundle-analyzer/lib/bin/analyzer.js dist/stats.json", - "prod": "npm-run-all prod:build:client prod:build:server run:prod:server", - "prod:build:client": "better-npm-run build_prod_client", - "prod:build:server": "better-npm-run build_prod_server", - "run:prod:server": "better-npm-run run_prod_server", - "jsdoc": "npm-run-all 'jsdoc:*'", - "jsdoc:src": "jsdoc -c jsdoc.src.json; : 'ignore minor errors'", - "jsdoc:api": "jsdoc -c jsdoc.api.json; : 'ignore minor errors'", - "lint": "./node_modules/eslint/bin/eslint.js -c .eslintrc src --format checkstyle --output-file eslint.xml", - "lint:fix": "./node_modules/eslint/bin/eslint.js -c .eslintrc src --fix", - "prettier": "./node_modules/prettier/bin-prettier.js -l 'src/**/*.js' 'src/**/*.jsx'", - "prettier:fix": "./node_modules/prettier/bin-prettier.js --write 'src/**/*.js' 'src/**/*.jsx'", - "watch:test:unit": "better-npm-run watch_test_unit", - "test": "npm-run-all lint test:unit", - "test:unit": "better-npm-run test_unit", - "test:unit:ci": "better-npm-run test_unit_ci", - "test:unit:fix": "yarn run test:unit -- -u", - "test:acceptance": "make test-acceptance", - "coverage": "npm-run-all test && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js", - "wait-for-frontend": "wget --retry-connrefused --spider ${PROTRACTOR_URL:-http://localhost:4300}", - "webdriver-update": "webdriver-manager update", - "docs": "raml2html docs/api/index.raml > src/static/docs/index.html", - "i18n": "npm-run-all i18n:sync i18n:build", - "i18n:sync": "babel-node scripts/i18n.js sync", - "i18n:build": "babel-node scripts/i18n.js build", - "styleguide": "styleguidist server" + "start": "razzle start", + "build": "razzle build", + "test": "razzle test --env=jsdom", + "start:prod": "NODE_ENV=production node build/server.js", + "i18n": "NODE_ENV=production node src/i18n.js" }, "jest": { - "testRegex": "(/__tests__/.*|\\.(test))\\.(js|jsx)$", "snapshotSerializers": [ "enzyme-to-json/serializer" ], @@ -79,7 +45,6 @@ "moduleNameMapper": { "~/config": "/src/config" }, - "collectCoverage": true, "coverageThreshold": { "global": { "branches": 10, @@ -88,244 +53,94 @@ "statements": 10 } }, - "globals": { - "__CLIENT__": true - }, "setupFiles": [ "./test-setup.js" ] }, - "betterScripts": { - "run_dev_client": { - "command": "babel-node webpack/server.dev.js", - "env": { - "PORT": 4301 - } - }, - "build_dev_server": { - "command": "webpack --config ./webpack/webpack.config.server.dev.entry.js --watch --hot --colors --display-error-details" - }, - "run_dev_server": { - "command": "nodemon --watch ./src/server.jsx --watch ./src --watch ./dist/server.js ./src/start-server.js --exec babel-node", - "env": { - "PORT": 4300, - "DEBUG": "plone-react:*", - "DEBUG_LEVELS": "trace" - } - }, - "build_prod_client": { - "command": "webpack --colors --display-error-details --config ./webpack/webpack.config.client.prod.entry.js" - }, - "build_prod_server": { - "command": "webpack --colors --display-error-details --config ./webpack/webpack.config.server.prod.entry.js" - }, - "run_prod_server": { - "command": "./node_modules/.bin/babel-node ./src/start-server-prod.js", - "env": { - "PORT": 4300 - } - }, - "test_unit": "jest --no-cache --runInBand", - "test_unit_ci": "jest --no-cache --runInBand --testResultsProcessor='jest-junit' --coverage", - "watch_test_unit": "jest --watch --no-cache --runInBand" + "prettier": { + "trailingComma": "all", + "singleQuote": true + }, + "engines": { + "node": "~8.11.3" }, "dependencies": { - "babel-cli": "6.26.0", - "babel-core": "6.26.0", - "babel-loader": "7.1.4", + "autoprefixer": "9.1.5", + "babel-core": "6.26.3", + "babel-loader": "8.0.2", "babel-plugin-add-module-exports": "0.2.1", - "babel-plugin-add-react-displayname": "0.0.5", "babel-plugin-react-intl": "2.4.0", - "babel-plugin-transform-decorators-legacy": "1.3.4", - "babel-plugin-transform-runtime": "6.23.0", - "babel-polyfill": "6.26.0", - "babel-preset-es2015": "6.24.1", - "babel-preset-react": "6.24.1", + "babel-plugin-root-import": "6.1.0", + "babel-plugin-transform-decorators-legacy": "1.3.5", "babel-preset-stage-0": "6.24.1", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "body-parser": "1.18.2", - "client-sessions": "0.8.0", - "compression": "1.7.2", - "copy-webpack-plugin": "4.5.1", - "coveralls": "3.0.0", - "debug": "3.1.0", - "debug-logger": "0.4.1", - "decorate-component-with-props": "1.1.0", - "diff": "3.5.0", + "connected-react-router": "4.4.1", + "coveralls": "3.0.2", + "css-loader": "1.0.0", "draft-js": "0.10.5", - "draft-js-anchor-plugin": "2.0.1", "draft-js-block-breakout-plugin": "2.0.1", "draft-js-buttons": "2.0.1", - "draft-js-export-html": "1.2.0", "draft-js-import-html": "1.2.1", "draft-js-inline-toolbar-plugin": "2.0.1", "draft-js-plugins-editor": "2.0.4", - "draft-js-plugins-utils": "2.0.2", - "es6-error": "4.1.1", + "draft-js-plugins-utils": "2.0.3", + "enzyme": "3.6.0", + "enzyme-adapter-react-15": "1.1.0", + "enzyme-to-json": "3.3.4", + "eslint-config-airbnb": "16.1.0", + "eslint-config-prettier": "2.9.0", + "eslint-plugin-prettier": "2.6.0", "express": "4.16.3", - "express-healthcheck": "0.1.0", - "file-loader": "1.1.11", - "filesize": "3.6.1", - "frameguard": "3.0.0", - "glob": "7.1.2", - "hoist-non-react-statics": "2.5.0", - "http-proxy": "1.16.2", - "immutability-helper": "2.6.6", - "immutable": "3.8.2", - "invariant": "2.2.4", - "ismobilejs": "0.4.1", + "glob": "7.1.3", + "history": "4.7.2", "jest-css-modules": "1.1.0", "jest-file": "1.0.0", - "jsonwebtoken": "8.2.0", + "jsonwebtoken": "8.3.0", "jwt-decode": "2.2.0", "less": "2.7.3", "less-loader": "4.1.0", "locale": "0.1.0", - "lodash": "4.17.5", + "lodash": "4.17.11", "lodash-move": "1.1.1", - "lru-memoize": "1.0.2", - "map-props": "1.0.0", - "moment": "2.22.0", - "multireducer": "3.1.1", - "path": "0.12.7", - "piping": "1.0.0-rc.4", + "moment": "2.22.2", "pofile": "1.0.10", - "prepend-http": "2.0.0", - "prettier": "1.14.2", - "prettier-stylelint": "0.4.2", - "pretty-error": "2.1.1", + "postcss-flexbugs-fixes": "4.1.0", + "postcss-loader": "3.0.0", + "prettier": "1.14.3", "promise-file-reader": "1.0.2", - "prop-types": "15.6.1", - "raven": "2.4.2", - "raven-js": "3.24.0", + "query-string": "6.1.0", + "raven": "2.6.4", + "raven-js": "3.27.0", + "razzle": "2.4.0", "react": "16.5.0", "react-cookie": "1.0.5", - "react-dnd": "2.6.0", - "react-dnd-html5-backend": "2.6.0", + "react-dnd": "5.0.0", + "react-dnd-html5-backend": "5.0.1", "react-dom": "16.5.0", - "react-dropzone": "4.2.9", + "react-dropzone": "5.1.0", "react-helmet": "5.2.0", - "react-inline-css": "2.3.1", - "react-intl": "2.4.0", - "react-intl-redux": "0.7.0", - "react-portal": "4.1.4", + "react-intl": "2.6.0", + "react-intl-redux": "2.0.2", + "react-portal": "4.1.5", "react-redux": "5.0.7", - "react-router": "3.0.5", - "react-router-redux": "4.0.8", - "react-share": "2.1.0", + "react-router-config": "1.0.0-beta.4", + "react-router-dom": "4.3.1", + "react-share": "2.3.1", "react-side-effect": "1.1.5", - "react-styleguidist": "7.0.1", + "react-test-renderer": "16.5.2", + "redux-mock-store": "1.5.3", "redraft": "0.10.1", - "redux": "3.7.2", - "redux-connect": "5.1.0", - "redux-logger": "3.0.6", - "redux-mock-store": "1.5.1", - "redux-thunk": "2.2.0", + "redux": "4.0.0", + "redux-connect": "8.0.0", + "redux-devtools-extension": "2.13.5", + "redux-thunk": "2.3.0", "semantic-ui-less": "2.3.1", - "semantic-ui-react": "0.79.0", - "serialize-javascript": "1.4.0", - "serve-favicon": "2.5.0", - "socket.io": "2.1.0", - "socket.io-client": "2.1.0", - "stylelint-config-idiomatic-order": "5.0.0", - "superagent": "3.8.2", - "tlds": "1.203.1", - "union-class-names": "1.0.0", - "universal-webpack": "0.6.2", - "url-loader": "1.0.1", - "uuid": "3.2.1", - "warning": "3.0.0", - "webpack": "4.4.1", - "webpack-cli": "2.0.13" - }, - "devDependencies": { - "autoprefixer": "8.5.0", - "autoprefixer-loader": "3.2.0", - "babel-eslint": "8.2.2", - "babel-jest": "22.4.3", - "babel-plugin-react-transform": "3.0.0", - "babel-plugin-root-import": "6.0.0", - "babel-plugin-typecheck": "3.9.0", - "babel-preset-env": "1.6.1", - "babel-preset-jest": "22.4.3", - "better-npm-run": "0.1.0", - "case-sensitive-paths-webpack-plugin": "2.1.2", - "chai": "4.1.2", - "chai-as-promised": "7.1.1", - "chai-things": "0.2.0", - "clean-webpack-plugin": "0.1.19", - "concurrently": "3.5.1", - "css-loader": "0.28.11", - "dirty-chai": "2.0.1", - "enzyme": "3.3.0", - "enzyme-adapter-react-15": "1.0.5", - "enzyme-to-json": "3.3.3", - "eslint": "4.19.1", - "eslint-config-airbnb": "16.1.0", - "eslint-config-prettier": "2.9.0", - "eslint-import-resolver-babel-plugin-root-import": "1.1.1", - "eslint-loader": "2.0.0", - "eslint-plugin-import": "2.10.0", - "eslint-plugin-jsx-a11y": "6.0.3", - "eslint-plugin-prettier": "2.6.0", - "eslint-plugin-react": "7.7.0", - "estraverse": "4.2.0", - "estraverse-fb": "1.3.2", - "image-webpack-loader": "4.2.0", - "jest": "22.4.3", - "jsdoc": "3.5.5", - "json-loader": "0.5.7", - "mini-css-extract-plugin": "0.4.0", - "node-sass": "4.8.3", - "nodemon": "1.17.3", - "npm-run-all": "4.1.2", - "postcss-flexbugs-fixes": "3.3.1", - "postcss-loader": "2.1.5", - "react-a11y": "1.0.0", - "react-addons-test-utils": "15.6.2", - "react-stateless-wrapper": "1.0.7", - "react-templates": "0.6.1", - "react-test-renderer": "16.5.0", - "react-transform-catch-errors": "1.0.2", - "react-transform-hmr": "1.0.4", - "redbox-react": "1.5.0", - "redux-devtools": "3.4.1", - "redux-devtools-dock-monitor": "1.1.3", - "redux-devtools-log-monitor": "1.4.0", - "sass-loader": "6.0.7", - "secure-random-string": "1.1.0", - "style-loader": "0.20.3", - "stylelint": "9.2.0", - "stylelint-config-standard": "18.2.0", - "supertest": "3.0.0", - "supertest-as-promised": "4.0.2", + "semantic-ui-react": "0.82.5", + "serialize-javascript": "1.5.0", + "style-loader": "0.23.0", + "superagent": "4.0.0-beta.5", "svg-loader": "0.0.2", "svgo": "1.0.5", "svgo-loader": "2.1.0", - "timekeeper": "2.1.0", - "webpack-bundle-analyzer": "2.11.1", - "webpack-dev-middleware": "3.1.0", - "webpack-hot-middleware": "2.21.2" - }, - "engines": { - "node": "~8.11.3" - }, - "bin": { - "better-npm-run": "./node_modules/better-npm-run/index.js", - "npm-run-all": "./node_modules/npm-run-all/bin/npm-run-all/index.js", - "webpack": "./node_modules/webpack/bin/webpack.js" - }, - "prettier": { - "trailingComma": "all", - "singleQuote": true - }, - "stylelint": { - "extends": [ - "stylelint-config-standard", - "stylelint-config-idiomatic-order", - "./node_modules/prettier-stylelint/config.js" - ] - }, - "sideEffects": false + "tlds": "1.203.1" + } } diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000..f2fd6517fa Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000000..54fb98911d --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * + diff --git a/razzle.config.js b/razzle.config.js new file mode 100644 index 0000000000..6f32786c34 --- /dev/null +++ b/razzle.config.js @@ -0,0 +1,168 @@ +const path = require('path'); +const autoprefixer = require('autoprefixer'); +const makeLoaderFinder = require('razzle-dev-utils/makeLoaderFinder'); +const nodeExternals = require('webpack-node-externals'); +const fs = require('fs'); + +const fileLoaderFinder = makeLoaderFinder('file-loader'); +const eslintLoaderFinder = makeLoaderFinder('eslint-loader'); + +const projectRootPath = path.resolve('.'); + +const packageJson = require(path.join(projectRootPath, 'package.json')); + +module.exports = { + modify: (config, { target, dev }, webpack) => { + const BASE_CSS_LOADER = { + loader: 'css-loader', + options: { + importLoaders: 2, + sourceMap: true, + localIdentName: '[name]__[local]___[hash:base64:5]', + }, + }; + + const POST_CSS_LOADER = { + loader: require.resolve('postcss-loader'), + options: { + // Necessary for external CSS imports to work + // https://github.com/facebookincubator/create-react-app/issues/2677 + ident: 'postcss', + plugins: () => [ + require('postcss-flexbugs-fixes'), + autoprefixer({ + browsers: [ + '>1%', + 'last 4 versions', + 'Firefox ESR', + 'not ie < 9', // React doesn't support IE8 anyway + ], + flexbox: 'no-2009', + }), + ], + }, + }; + + const LESSLOADER = { + test: /\.less$/, + include: [path.resolve('./theme'), /node_modules\/semantic-ui-less/], + use: [ + { + loader: 'style-loader', + }, + BASE_CSS_LOADER, + POST_CSS_LOADER, + { + loader: 'less-loader', + options: { + outputStyle: 'expanded', + sourceMap: true, + }, + }, + ], + }; + + const SVGLOADER = { + test: /icons\/.*\.svg$/, + use: [ + { + loader: 'svg-loader', + }, + { + loader: 'svgo-loader', + options: { + plugins: [ + { removeTitle: true }, + { convertPathData: false }, + { removeUselessStrokeAndFill: true }, + { removeViewBox: false }, + ], + }, + }, + ], + }; + + if (target === 'web') { + config.plugins.unshift( + new webpack.DefinePlugin({ + __CLIENT__: true, + __SERVER__: false, + }), + ); + } + + if (target === 'node') { + config.plugins.unshift( + new webpack.DefinePlugin({ + __CLIENT__: false, + __SERVER__: true, + }), + ); + } + + config.module.rules.push(LESSLOADER); + config.module.rules.push(SVGLOADER); + + // Don't load config|variables|overrides) files with file-loader + // Don't load SVGs from ./src/icons with file-loader + const fileLoader = config.module.rules.find(fileLoaderFinder); + fileLoader.exclude = [ + /\.(config|variables|overrides)$/, + /icons\/.*\.svg$/, + ...fileLoader.exclude, + ]; + + // Disabling the ESlint pre loader + config.module.rules.splice(0, 1); + + const customizations = packageJson.customizations + ? packageJson.customizations + : {}; + + config.resolve.alias = { + ...config.resolve.alias, + '../../theme.config$': `${projectRootPath}/theme/theme.config`, + '@plone/plone-react': `${projectRootPath}/node_modules/@plone/plone-react/src/`, + ...customizations, + }; + + config.performance = { + maxAssetSize: 10000000, + maxEntrypointSize: 10000000, + }; + + const babelRuleIndex = config.module.rules.findIndex( + rule => + rule.use && + rule.use[0].loader && + rule.use[0].loader.includes('babel-loader'), + ); + const { include } = config.module.rules[babelRuleIndex]; + if (fs.existsSync('./node_modules/@plone/plone-react/src')) { + include.push(fs.realpathSync('./node_modules/@plone/plone-react/src')); + } + config.module.rules[babelRuleIndex] = Object.assign( + config.module.rules[babelRuleIndex], + { + include, + }, + ); + config.externals = + target === 'node' + ? [ + nodeExternals({ + whitelist: [ + dev ? 'webpack/hot/poll?300' : null, + /\.(eot|woff|woff2|ttf|otf)$/, + /\.(svg|png|jpg|jpeg|gif|ico)$/, + /\.(mp4|mp3|ogg|swf|webp)$/, + /\.(css|scss|sass|sss|less)$/, + /^@plone\/plone-react/, + ].filter(Boolean), + }), + ] + : []; + + return config; + }, +}; diff --git a/server.babel.js b/server.babel.js deleted file mode 100644 index c391a927f4..0000000000 --- a/server.babel.js +++ /dev/null @@ -1,15 +0,0 @@ -// enable runtime transpilation to use ES6/7 in node - -var fs = require('fs'); - -var babelrc = fs.readFileSync('./.babelrc'); -var config; - -try { - config = JSON.parse(babelrc); -} catch (err) { - console.error('==> ERROR: Error parsing your .babelrc.'); - console.error(err); -} - -require('babel-register')(config); diff --git a/src/client.js b/src/client.js new file mode 100644 index 0000000000..74002d356d --- /dev/null +++ b/src/client.js @@ -0,0 +1,3 @@ +import client from './start-client'; + +client(); diff --git a/src/client.jsx b/src/client.jsx deleted file mode 100644 index 2aa34956ba..0000000000 --- a/src/client.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import 'babel-polyfill'; - -import React from 'react'; -import { hydrate } from 'react-dom'; -import { Provider } from 'react-intl-redux'; -import { ReduxAsyncConnect } from 'redux-connect'; -import { browserHistory, Router } from 'react-router'; -import { syncHistoryWithStore } from 'react-router-redux'; -import nlLocaleData from 'react-intl/locale-data/nl'; -import deLocaleData from 'react-intl/locale-data/de'; -import enLocaleData from 'react-intl/locale-data/en'; -import { addLocaleData } from 'react-intl'; -import 'semantic-ui-less/semantic.less'; - -import configureStore from './store'; -import getRoutes from './routes'; -import { Api, persistAuthToken } from './helpers'; - -const api = new Api(); -const initialState = window.__data; // eslint-disable-line no-underscore-dangle -const store = configureStore(initialState, undefined, false, api); -const history = syncHistoryWithStore(browserHistory, store); -addLocaleData([...nlLocaleData, ...deLocaleData, ...enLocaleData]); -persistAuthToken(store); - -hydrate( - - } - history={history} - > - {getRoutes(store)} - - , - document.getElementById('main'), -); - -if (module.hot) { - module.hot.accept(); -} diff --git a/src/components/manage/Actions/Actions.jsx b/src/components/manage/Actions/Actions.jsx index 65e86af38b..1ede40f9f5 100644 --- a/src/components/manage/Actions/Actions.jsx +++ b/src/components/manage/Actions/Actions.jsx @@ -6,7 +6,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; import { bindActionCreators } from 'redux'; import { Dropdown, Icon } from 'semantic-ui-react'; import { diff --git a/src/components/manage/Actions/Actions.test.jsx b/src/components/manage/Actions/Actions.test.jsx index 7b6f440bfb..3c5a3018a8 100644 --- a/src/components/manage/Actions/Actions.test.jsx +++ b/src/components/manage/Actions/Actions.test.jsx @@ -2,6 +2,7 @@ import React from 'react'; import renderer from 'react-test-renderer'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; +import MemoryRouter from 'react-router-dom/MemoryRouter'; import Actions from './Actions'; @@ -122,7 +123,9 @@ describe('Actions', () => { }); const component = renderer.create( - + + + , ); const json = component.toJSON(); diff --git a/src/components/manage/Actions/__snapshots__/Actions.test.jsx.snap b/src/components/manage/Actions/__snapshots__/Actions.test.jsx.snap index 31c6468d8c..0df8c3fe9a 100644 --- a/src/components/manage/Actions/__snapshots__/Actions.test.jsx.snap +++ b/src/components/manage/Actions/__snapshots__/Actions.test.jsx.snap @@ -2,10 +2,7 @@ exports[`Actions renders an actions component 1`] = `