diff --git a/.babelrc.js b/.babelrc.js index 28adc2a..659aad0 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -1,13 +1,9 @@ /** * Created by: Andrey Polyakov (andrey@polyakov.im) */ -const {argv} = require('yargs'); module.exports = (api) => { - const env = argv.env || []; - const mode = !!env.find((value) => value === 'mode=dev') - ? 'development' - : 'production'; + const mode = process.env.NODE_ENV ?? 'production'; // This caches the Babel config by environment. api.cache.using(() => mode); diff --git a/.eslintrc.js b/.eslintrc.js index 1e7e1e4..4e27d96 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -8,8 +8,7 @@ module.exports = { }, extends: [ 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin - 'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier - 'prettier/react', // disables react-specific linting rules that conflict with prettier + 'prettier', ], parserOptions: { project: path.resolve(__dirname, './tsconfig.json'), diff --git a/package.json b/package.json index 096cc5b..7937ee5 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "webpack-typescript-react", - "version": "1.0.2", + "version": "1.0.7", "description": "Webpack 5 boilerplate with support of most common loaders and modules", "keywords": [ "react", @@ -17,93 +17,94 @@ "author": "Andrey Polyakov ", "main": "webpack.config.babel.js", "scripts": { - "build": "webpack --config webpack.config.babel.js", - "profile": "webpack --profile --json --config webpack.config.babel.js > ./dist/profile.json && webpack-bundle-analyzer ./dist/profile.json", - "start": "webpack --env mode=dev --env isDevServer --env NODE_ENV=local serve --config webpack.config.babel.js" + "build": "cross-env NODE_ENV=production webpack --config webpack.config.babel.js", + "profile": "cross-env NODE_ENV=production webpack --profile --json --config webpack.config.babel.js > ./dist/profile.json && webpack-bundle-analyzer ./dist/profile.json", + "start": "cross-env WEBPACK_IS_DEV_SERVER=true NODE_ENV=development webpack serve --config webpack.config.babel.js", + "release": "npm version patch", + "update-hooks": "npx simple-git-hooks", + "prerelease": "npm run update-hooks", + "postinstall": "npm run update-hooks" }, - "husky": { - "hooks": { - "pre-commit": "lint-staged", - "post-commit": "git update-index --again" - } + "simple-git-hooks": { + "pre-commit": "npx lint-staged", + "post-commit": "git update-index --again" }, "dependencies": { - "@types/classnames": "^2.2.10", - "@types/react": "^16.9.53", - "@types/react-dom": "^16.9.8", - "classnames": "^2.2.6", + "@types/classnames": "^2.3.0", + "@types/react": "^17.0.38", + "@types/react-dom": "^17.0.11", + "classnames": "^2.3.1", "normalize.css": "^8.0.1", - "react": "^17.0.1", - "react-dom": "^17.0.1" + "react": "^17.0.2", + "react-dom": "^17.0.2" }, "devDependencies": { - "@babel/core": "~7.12.3", - "@babel/plugin-proposal-class-properties": "~7.12.1", - "@babel/plugin-proposal-export-default-from": "^7.12.1", - "@babel/plugin-proposal-export-namespace-from": "~7.12.1", - "@babel/plugin-proposal-object-rest-spread": "~7.12.1", - "@babel/plugin-proposal-throw-expressions": "~7.12.1", + "@babel/core": "~7.16.7", + "@babel/plugin-proposal-class-properties": "~7.16.7", + "@babel/plugin-proposal-export-default-from": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "~7.16.7", + "@babel/plugin-proposal-object-rest-spread": "~7.16.7", + "@babel/plugin-proposal-throw-expressions": "~7.16.7", "@babel/plugin-syntax-dynamic-import": "~7.8.3", - "@babel/plugin-transform-runtime": "~7.12.1", - "@babel/preset-env": "~7.12.1", - "@babel/preset-react": "~7.12.1", - "@babel/register": "~7.12.1", - "@pmmmwh/react-refresh-webpack-plugin": "~0.4.2", - "@svgr/webpack": "~5.4.0", - "@teamsupercell/typings-for-css-modules-loader": "~2.4.0", - "@typescript-eslint/eslint-plugin": "~4.7.0", - "@typescript-eslint/parser": "~4.7.0", - "autoprefixer": "~10.0.1", + "@babel/plugin-transform-runtime": "~7.16.7", + "@babel/preset-env": "~7.16.7", + "@babel/preset-react": "~7.16.7", + "@babel/register": "~7.16.7", + "@pmmmwh/react-refresh-webpack-plugin": "~0.5.4", + "@svgr/webpack": "~6.1.2", + "@teamsupercell/typings-for-css-modules-loader": "~2.5.1", + "@typescript-eslint/eslint-plugin": "~5.9.0", + "@typescript-eslint/parser": "~5.9.0", + "autoprefixer": "~10.4.2", "babel-eslint": "~10.1.0", - "babel-loader": "~8.2.1", - "clean-webpack-plugin": "~3.0.0", - "copy-webpack-plugin": "~6.3.0", - "core-js": "~3.7.0", - "css-loader": "~5.0.0", - "cssnano": "~4.1.10", - "eslint": "~7.13.0", - "eslint-config-airbnb-base": "~14.2.0", - "eslint-config-airbnb-typescript": "~12.0.0", - "eslint-config-prettier": "~6.15.0", + "babel-loader": "~8.2.3", + "clean-webpack-plugin": "~4.0.0", + "copy-webpack-plugin": "~10.2.0", + "core-js": "~3.20.2", + "cross-env": "^7.0.3", + "css-loader": "~6.5.1", + "cssnano": "~5.0.15", + "eslint": "~8.6.0", + "eslint-config-airbnb-base": "~15.0.0", + "eslint-config-airbnb-typescript": "~16.1.0", + "eslint-config-prettier": "~8.3.0", "eslint-import-resolver-alias": "~1.1.2", - "eslint-plugin-import": "~2.22.1", - "eslint-plugin-jsx-a11y": "~6.4.1", - "eslint-plugin-react": "~7.21.5", - "eslint-plugin-react-hooks": "~4.2.0", - "eslint-webpack-plugin": "~2.2.1", - "fork-ts-checker-webpack-plugin": "~6.0.1", - "html-loader": "~1.3.2", - "html-webpack-plugin": "~5.0.0-alpha.6", - "husky": "~4.3.0", + "eslint-plugin-import": "~2.25.4", + "eslint-plugin-jsx-a11y": "~6.5.1", + "eslint-plugin-react": "~7.28.0", + "eslint-plugin-react-hooks": "~4.3.0", + "eslint-webpack-plugin": "~3.1.1", + "fork-ts-checker-webpack-plugin": "~6.5.0", + "html-loader": "~3.1.0", + "html-webpack-plugin": "~5.5.0", "import-sort-style-module-and-prefix": "~0.1.3", - "is-windows": "~1.0.2", - "less": "~3.12.2", - "less-loader": "~7.0.2", - "lint-staged": "~10.5.0", - "mini-css-extract-plugin": "~1.3.0", + "less": "~4.1.2", + "less-loader": "~10.2.0", + "mini-css-extract-plugin": "~2.4.6", "path": "~0.12.7", - "postcss-loader": "~4.0.4", - "prettier": "~2.1.2", - "prettier-plugin-import-sort": "~0.0.6", - "pretty-quick": "~3.1.0", - "react-refresh": "~0.9.0", - "regenerator-runtime": "~0.13.7", - "resolve-url-loader": "~3.1.2", - "sass": "~1.29.0", - "sass-loader": "~10.0.4", - "sass-resources-loader": "~2.1.1", - "style-loader": "~2.0.0", - "svg-url-loader": "~6.0.0", - "terser-webpack-plugin": "~5.0.1", - "ts-loader": "~8.0.7", - "typescript": "~4.0.3", + "postcss": "~8.4.5", + "postcss-loader": "~6.2.1", + "prettier": "~2.5.1", + "prettier-plugin-import-sort": "~0.0.7", + "pretty-quick": "~3.1.3", + "react-refresh": "~0.11.0", + "regenerator-runtime": "~0.13.9", + "resolve-url-loader": "~4.0.0", + "sass": "~1.47.0", + "sass-loader": "~12.4.0", + "sass-resources-loader": "~2.2.4", + "simple-git-hooks": "^2.7.0", + "style-loader": "~3.3.1", + "svg-url-loader": "~7.1.1", + "terser-webpack-plugin": "~5.3.0", + "ts-loader": "~9.2.6", + "typescript": "~4.5.4", "url-loader": "~4.1.1", - "webpack": "~5.4.0", - "webpack-bundle-analyzer": "~4.1.0", - "webpack-cli": "~4.2.0", - "webpack-dev-server": "~3.11.0", - "webpack-merge": "~5.3.0", - "yargs": "~16.1.0" + "webpack": "~5.65.0", + "webpack-bundle-analyzer": "~4.5.0", + "webpack-cli": "~4.9.1", + "webpack-dev-server": "~4.7.2", + "webpack-merge": "~5.8.0" }, "importSort": { ".ts, .tsx": { diff --git a/src/@types/declarations.d.ts b/src/@types/declarations.d.ts index 61aaf0b..d4cf03c 100644 --- a/src/@types/declarations.d.ts +++ b/src/@types/declarations.d.ts @@ -14,6 +14,11 @@ declare module "*.svg" { export default ReactComponent; } +declare module '*.json' { + const content: Record; + export default content; +} + declare const IS_PROD: boolean; declare const IS_DEV: boolean; declare const IS_DEV_SERVER: boolean; diff --git a/src/components/app/app.module.scss b/src/components/app/app.module.scss index 3d2317f..ca20fa5 100644 --- a/src/components/app/app.module.scss +++ b/src/components/app/app.module.scss @@ -12,4 +12,16 @@ height: $size; margin: 25px 0 0 0; } + + &-link { + display: block; + margin: 20px 0 0 0; + font-family: 'Open Sans', sans-serif; + font-weight: 400; + color: #fff; + text-decoration: none; + &:hover { + color: #e8e8e8; + } + } } diff --git a/src/components/app/app.module.scss.d.ts b/src/components/app/app.module.scss.d.ts index fd217f7..ca03498 100644 --- a/src/components/app/app.module.scss.d.ts +++ b/src/components/app/app.module.scss.d.ts @@ -4,6 +4,7 @@ declare namespace AppModuleScssNamespace { export interface IAppModuleScss { stylesHeader: string; stylesImage: string; + stylesLink: string; } } diff --git a/src/components/app/app.tsx b/src/components/app/app.tsx index 17db8d2..09db5ab 100644 --- a/src/components/app/app.tsx +++ b/src/components/app/app.tsx @@ -1,10 +1,13 @@ /** * Created by: Andrey Polyakov (andrey@polyakov.im) */ + +import cn from 'classnames'; import React, {Suspense, lazy} from 'react'; +import packageJson from '../../../package.json'; import {stylesContainer} from './app.module.less'; -import {stylesHeader, stylesImage} from './app.module.scss'; +import {stylesHeader, stylesImage, stylesLink} from './app.module.scss'; const LazyStrawberryIcon = lazy(() => import('./strawberry')); export const App = (): React.ReactElement => ( @@ -13,5 +16,14 @@ export const App = (): React.ReactElement => ( +
+ + @glook/webpack-typescript-react ({packageJson.version}) + +
); diff --git a/src/index.html b/src/index.html index 9c4c9bb..d93477e 100644 --- a/src/index.html +++ b/src/index.html @@ -2,9 +2,15 @@ + Codestin Search App + + diff --git a/src/index.tsx b/src/index.tsx index 2b46856..c28f833 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,3 +1,4 @@ +import '@styles/styles.css'; /** * Created by: Andrey Polyakov (andrey@polyakov.im) */ diff --git a/src/styles/styles.css b/src/styles/styles.css new file mode 100644 index 0000000..9683422 --- /dev/null +++ b/src/styles/styles.css @@ -0,0 +1,3 @@ +#root { + background: #fff; +} diff --git a/tsconfig.json b/tsconfig.json index c74384e..41f6b8c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "./dist", "module": "esnext", - "target": "es5", + "target": "es6", "lib": ["es6", "dom"], "sourceMap": true, "allowJs": true, @@ -23,7 +23,9 @@ }, "allowSyntheticDefaultImports": true, "esModuleInterop": true, - "importsNotUsedAsValues": "preserve" + "importsNotUsedAsValues": "preserve", + "incremental": true }, - "exclude": ["node_modules", "webpack"] + "include": ["src"], + "exclude": ["**/node_modules", "**/.*/"] } diff --git a/webpack.config.babel.js b/webpack.config.babel.js index cade55d..66ddecc 100644 --- a/webpack.config.babel.js +++ b/webpack.config.babel.js @@ -5,8 +5,8 @@ import merge from 'webpack-merge'; import baseConfig from './webpack/base'; import devConfig from './webpack/dev'; -import {isProd} from './webpack/utils/env'; import prodConfig from './webpack/prod'; +import {isProd} from './webpack/utils/env'; export default () => isProd ? merge(baseConfig, prodConfig) : merge(baseConfig, devConfig); diff --git a/webpack/base.js b/webpack/base.js index 52de5c8..fd3496f 100755 --- a/webpack/base.js +++ b/webpack/base.js @@ -3,7 +3,7 @@ */ import path from 'path'; -import {aliasItems, devServerUrl, externalItems} from './config'; +import {aliasItems, externalItems} from './config'; import entry from './entry'; import optimization from './optimization'; import * as plugins from './plugins'; @@ -18,7 +18,7 @@ export default { entry, output: { path: path.join(__dirname, '../dist'), - publicPath: isDevServer ? devServerUrl : './', + publicPath: isDevServer ? undefined : './', filename: isDevServer ? '[name].[fullhash].js' : '[name].[contenthash].js', diff --git a/webpack/config/devServer.js b/webpack/config/devServer.js index d0d7070..e182fbe 100644 --- a/webpack/config/devServer.js +++ b/webpack/config/devServer.js @@ -2,23 +2,18 @@ * Created by: Andrey Polyakov (andrey@polyakov.im) * @see https://webpack.js.org/configuration/dev-server/ */ -import isWindows from 'is-windows'; import {devServerProxyConfig} from './devServierProxy'; -const defaultPort = 8080; - -const devServerHost = isWindows() ? '127.0.0.1' : '0.0.0.0'; - -export const devServerUrl = `http://${devServerHost}:${defaultPort}/`; - export const devServerConfig = { - publicPath: '/', - port: defaultPort, - historyApiFallback: true, + client: { + overlay: false, + }, headers: {'Access-Control-Allow-Origin': '*'}, - proxy: devServerProxyConfig, + historyApiFallback: true, hot: true, - overlay: false, - host: devServerHost, + proxy: devServerProxyConfig, + static: { + publicPath: '/', + }, }; diff --git a/webpack/config/devServierProxy.js b/webpack/config/devServierProxy.js index f65b4ef..96ca778 100644 --- a/webpack/config/devServierProxy.js +++ b/webpack/config/devServierProxy.js @@ -15,6 +15,8 @@ const httpsProxyTarget = { }; export const devServerProxyConfig = { + /* + // Example proxy configuration endpoins '/world-time': { target: `${httpsProxyTarget.protocol}://worldtimeapi.org:${httpsProxyTarget.port}`, pathRewrite: pathRewrite('^/world-time/test', '/api'), @@ -27,4 +29,5 @@ export const devServerProxyConfig = { changeOrigin: true, secure: false, }, + */ }; diff --git a/webpack/plugins/pluginCleanWebpack.js b/webpack/plugins/pluginCleanWebpack.js index 8a82a83..67d1ced 100644 --- a/webpack/plugins/pluginCleanWebpack.js +++ b/webpack/plugins/pluginCleanWebpack.js @@ -4,7 +4,11 @@ import {CleanWebpackPlugin} from 'clean-webpack-plugin'; const config = { - cleanOnceBeforeBuildPatterns: ['**/*', '!profile.json'], + cleanOnceBeforeBuildPatterns: [ + '**/*', + '!profile.json', + '!tsconfig.tsbuildinfo', + ], }; export const cleanWebpackPlugin = new CleanWebpackPlugin(config); diff --git a/webpack/plugins/pluginForkTsChecker.js b/webpack/plugins/pluginForkTsChecker.js index e9c1956..ad95d63 100644 --- a/webpack/plugins/pluginForkTsChecker.js +++ b/webpack/plugins/pluginForkTsChecker.js @@ -13,7 +13,6 @@ const config = { configFile: join(rootDir, '/tsconfig.json'), }, eslint: {enabled: true, files: '../src/**/*.{ts,tsx,js,jsx}'}, - logger: {infrastructure: 'silent', issues: 'console'}, }; export const forkTsCheckerWebpackPlugin = new ForkTsCheckerWebpackPlugin( diff --git a/webpack/rules/styles.js b/webpack/rules/styles.js index 7d3e2d0..686c29d 100644 --- a/webpack/rules/styles.js +++ b/webpack/rules/styles.js @@ -16,7 +16,7 @@ import { /** css **/ export const cssRule = { test: /\.css$/, - use: [miniCssExtractLoader, postCssLoader, resolveUrlLoader, cssLoader], + use: [miniCssExtractLoader, cssLoader, postCssLoader], }; /** less **/ diff --git a/webpack/utils/env.js b/webpack/utils/env.js index 3e34d54..318df78 100644 --- a/webpack/utils/env.js +++ b/webpack/utils/env.js @@ -3,12 +3,10 @@ */ import {join} from 'path'; -import {parseArguments} from './helpers'; - -const parsedArguments = parseArguments(); -export const mode = parsedArguments.mode ?? 'production'; -export const isDevServer = parsedArguments.isDevServer ?? false; +export const mode = process.env.NODE_ENV ?? 'production'; +export const isDevServer = process.env.WEBPACK_IS_DEV_SERVER === 'true'; export const isProd = mode === 'production'; export const isDev = !isProd; export const rootDir = join(__dirname, '../../'); export const webpackDir = join(__dirname, '../'); +export const defaultPort = 8080; diff --git a/webpack/utils/helpers.js b/webpack/utils/helpers.js index 263db12..124f38d 100644 --- a/webpack/utils/helpers.js +++ b/webpack/utils/helpers.js @@ -1,16 +1,6 @@ /** * Created by: Andrey Polyakov (andrey@polyakov.im) */ -import {argv} from 'yargs'; - -export const parseArguments = () => { - const {env = []} = argv; - return env.reduce((accumulator, currentValue) => { - const [key, value = true] = currentValue.split('='); - return {...accumulator, [key]: value}; - }, {}); -}; - export const arrayFilterEmpty = (array) => array.filter((x) => !!x); export const pathRewrite = (localUrl, remoteUrl) => (path) =>