diff --git a/package-lock.json b/package-lock.json index 351d452..567373a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3775,8 +3775,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "dev": true, - "optional": true + "dev": true }, "bindings": { "version": "1.5.0", @@ -4241,7 +4240,6 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", "dev": true, - "optional": true, "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", @@ -4400,6 +4398,11 @@ "shallow-clone": "^0.1.2" } }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -5234,6 +5237,15 @@ "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", "dev": true }, + "dart-sass": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/dart-sass/-/dart-sass-1.25.0.tgz", + "integrity": "sha512-syNOAstJXAmvD3RifcDk3fiPMyYE2fY8so6w9gf2/wNlKpG0zyH+oiXubEYVOy1WAWkzOc72pbAxwx+3OU4JJA==", + "dev": true, + "requires": { + "chokidar": ">=2.0.0 <4.0.0" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -8718,7 +8730,6 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "optional": true, "requires": { "binary-extensions": "^2.0.0" } @@ -10711,8 +10722,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.0", @@ -11099,7 +11109,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -11842,8 +11851,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-copy": { "version": "0.1.0", @@ -13991,6 +13999,15 @@ } } }, + "react": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", + "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "react-app-polyfill": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz", @@ -14068,6 +14085,29 @@ } } }, + "react-dom": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz", + "integrity": "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.1" + }, + "dependencies": { + "scheduler": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.1.tgz", + "integrity": "sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } + } + }, "react-error-overlay": { "version": "6.0.8", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.8.tgz", @@ -14299,7 +14339,6 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", "dev": true, - "optional": true, "requires": { "picomatch": "^2.2.1" } diff --git a/package.json b/package.json index 6a165e5..156cf28 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,12 @@ "scripts": { "build": "tsc -p tsconfig-build.json", "test": "jest --config=jest.config.json", - "test-coverage": "jest --config=jest.config.json --collectCoverage" + "test-coverage": "jest --config=jest.config.json --collectCoverage", + "dev": "webpack serve --config www/webpack.config.js" }, "author": "Eran Machiels", "license": "ISC", "devDependencies": { - "typescript": "^4.0.3", "@babel/plugin-proposal-class-properties": "^7.10.4", "@babel/preset-env": "^7.11.0", "@babel/preset-react": "^7.10.4", @@ -23,14 +23,22 @@ "@types/react-is": "^16.7.1", "@typescript-eslint/eslint-plugin": "^4.5.0", "@typescript-eslint/parser": "^4.5.0", + "dart-sass": "^1.25.0", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.3", "eslint": "^7.7.0", "eslint-plugin-react": "^7.20.6", "flush-promises": "^1.0.2", + "react-dom": "^17.0.1", "react-scripts": "^4.0.0", "react-test-renderer": "^17.0.1", "ts-loader": "^8.0.2", - "webpack-cli": "^4.1.0" + "typescript": "^4.0.3", + "webpack-cli": "^4.1.0", + "webpack-dev-server": "^3.11.0" + }, + "dependencies": { + "clsx": "^1.1.1", + "react": "^17.0.1" } } diff --git a/tsconfig.json b/tsconfig.json index 94d9d54..f2acd7d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -43,6 +43,7 @@ "exclude": [ "node_modules", "dist", - "setupTests.ts" + "setupTests.ts", + "www" ] } diff --git a/www/.env b/www/.env new file mode 100644 index 0000000..e69de29 diff --git a/www/public/favicon.ico b/www/public/favicon.ico new file mode 100644 index 0000000..a11777c Binary files /dev/null and b/www/public/favicon.ico differ diff --git a/www/public/index.html b/www/public/index.html new file mode 100644 index 0000000..6bbff76 --- /dev/null +++ b/www/public/index.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + React App + + + +
+ + + diff --git a/www/public/robots.txt b/www/public/robots.txt new file mode 100644 index 0000000..01b0f9a --- /dev/null +++ b/www/public/robots.txt @@ -0,0 +1,2 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * diff --git a/www/src/index.tsx b/www/src/index.tsx new file mode 100644 index 0000000..53b8db1 --- /dev/null +++ b/www/src/index.tsx @@ -0,0 +1,7 @@ +import * as React from 'react'; +import * as ReactDom from 'react-dom'; + +ReactDom.render( + null, + document.getElementById('root') +); diff --git a/www/webpack.config.js b/www/webpack.config.js new file mode 100644 index 0000000..6abdd64 --- /dev/null +++ b/www/webpack.config.js @@ -0,0 +1,80 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const webpack = require('webpack'); +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const WebpackManifestPlugin = require('webpack-manifest-plugin'); +const dotenv = require('dotenv'); + +/** + * Load env file and parse config, to be used when building the app + * @returns {webpack.DefinePlugin} + */ +const setEnvVars = () => { + const env = dotenv.config({ + path: './www/.env' + }).parsed; + + // loop over the keys and place them in the process.env namespace + const keys = Object.keys(env).reduce((prev, next) => { + prev[`process.env.${next}`] = JSON.stringify(env[next]); + return prev; + }, {}); + + return new webpack.DefinePlugin(keys); +}; + +module.exports = { + entry: { + main: './www/src/index.tsx' + }, + module: { + rules: [ + { + test: /\.ts(x|)?$/, + use: 'babel-loader', + exclude: /node_modules/ + }, { + test: /\.[s|]css$/, + use: [{ + loader: 'style-loader' + }, { + loader: 'css-loader' + }, { + loader: 'sass-loader', + options: { + implementation: require('dart-sass') + } + }] + }, { + test: /\.(png|svg|jpg|jpeg|gif|ico|woff2?)$/, + exclude: /node_modules/, + use: ['file-loader?name=[name].[ext]'] // ?name=[name].[ext] is only necessary to preserve the original file name + } + ] + }, + resolve: { + extensions: ['.tsx', '.ts', '.js', '.jsx'] + }, + plugins: [ + new HtmlWebpackPlugin({ + template: './www/public/index.html', + favicon: path.resolve(__dirname, 'public', 'favicon.ico') + }), + new WebpackManifestPlugin(), + setEnvVars() + ], + output: { + filename: '[name].[hash].js', + path: path.resolve(__dirname, 'www', 'public'), + publicPath: '/' + }, + mode: 'development', + devServer: { + host: 'localhost', + port: 3000, + open: true, + historyApiFallback: true, + publicPath: '/', + hot: true + } +};