diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index bf62130..0000000 --- a/.eslintrc +++ /dev/null @@ -1,39 +0,0 @@ -{ - "env": { - "browser": true, - "es2021": true, - "node": true, - "worker": true - }, - "extends": [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:react-hooks/recommended" - ], - "parserOptions": { - "sourceType": "module", - "requireConfigFile": false - }, - "rules": { - "no-use-before-define": [ - "error", - { - "functions": false - } - ], - "no-unused-vars": "warn", - "react/react-in-jsx-scope": "off" - }, - "globals": { - "process": "readonly" - }, - "settings": { - "react": { - "version": "detect" - } - }, - "ignorePatterns": [ - "/**/*.*", - "!src/**/*.*" - ] -} \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..b4cf0f5 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,61 @@ +const typescript = require('./wm-config').typescript + +module.exports = { + "root": true, + ...(typescript ? { "parser": "@typescript-eslint/parser" } : {}), + "plugins": [ + typescript && "@typescript-eslint" + ].filter(Boolean), + "env": { + "browser": true, + "es2021": true, + "node": true, + "worker": true + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended" + ], + "extends": [ + "eslint:recommended", + typescript && "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended" + ].filter(Boolean), + "parserOptions": { + "sourceType": "module", + "requireConfigFile": false + }, + "rules": { + ...(typescript ? { + "@typescript-eslint/no-use-before-define": [ + "error", + { + "functions": false + } + ] + } : { + "no-use-before-define": [ + "error", + { + "functions": false + } + ], + "no-unused-vars": "warn", + }), + "react/react-in-jsx-scope": "off" + }, + "globals": { + "process": "readonly" + }, + "settings": { + "react": { + "version": "detect" + } + }, + "ignorePatterns": [ + "/**/*.*", + "!src/**/*.*" + ] +} \ No newline at end of file diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..b09896b --- /dev/null +++ b/index.d.ts @@ -0,0 +1,20 @@ +/** images */ + +declare module "*.avif" +declare module "*.gif" +declare module "*.apng" +declare module '*.png' +declare module "*.jpg" +declare module "*.jpeg" +declare module "*.jfif" +declare module "*.pjpeg" +declare module "*.pjp" +declare module "*.svg" +declare module "*.webp" + +/** svg as react component */ +declare module "*.svg?react" + +/** other */ + +declare module "*.txt" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 471b951..f1a1150 100644 --- a/package-lock.json +++ b/package-lock.json @@ -617,6 +617,15 @@ "@babel/helper-plugin-utils": "^7.14.5" } }, + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, "@babel/plugin-transform-arrow-functions": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", @@ -960,6 +969,17 @@ "@babel/helper-plugin-utils": "^7.14.5" } }, + "@babel/plugin-transform-typescript": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.4.tgz", + "integrity": "sha512-sM1/FEjwYjXvMwu1PJStH11kJ154zd/lpY56NQJ5qH2D0mabMv1CAy/kdvS9RP4Xgfj9fBBA3JiSLdDHgXdzOA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-typescript": "^7.14.5" + } + }, "@babel/plugin-transform-unicode-escapes": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz", @@ -1087,6 +1107,17 @@ "@babel/plugin-transform-react-pure-annotations": "^7.14.5" } }, + "@babel/preset-typescript": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.15.0.tgz", + "integrity": "sha512-lt0Y/8V3y06Wq/8H/u0WakrqciZ7Fz7mwPDHWUJAXlABL5hiUG42BNlRXiELNjeWjO5rWmnNKlx+yzJvxezHow==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-transform-typescript": "^7.15.0" + } + }, "@babel/runtime": { "version": "7.15.4", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", @@ -1722,18 +1753,168 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/prop-types": { + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + }, "@types/q": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==", "dev": true }, + "@types/react": { + "version": "17.0.26", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.26.tgz", + "integrity": "sha512-MXxuXrH2xOcv5cp/su4oz69dNQnSA90JjFw5HBd5wifw6Ihi94j7dRJm7qNsB30tnruXSCPc9qmlhGop4nh9Hw==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "17.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", + "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", + "requires": { + "@types/react": "*" + } + }, "@types/retry": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.32.0.tgz", + "integrity": "sha512-+OWTuWRSbWI1KDK8iEyG/6uK2rTm3kpS38wuVifGUTDB6kjEuNrzBI1MUtxnkneuWG/23QehABe2zHHrj+4yuA==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.32.0", + "@typescript-eslint/scope-manager": "4.32.0", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.32.0.tgz", + "integrity": "sha512-WLoXcc+cQufxRYjTWr4kFt0DyEv6hDgSaFqYhIzQZ05cF+kXfqXdUh+//kgquPJVUBbL3oQGKQxwPbLxHRqm6A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.32.0", + "@typescript-eslint/types": "4.32.0", + "@typescript-eslint/typescript-estree": "4.32.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "4.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.32.0.tgz", + "integrity": "sha512-lhtYqQ2iEPV5JqV7K+uOVlPePjClj4dOw7K4/Z1F2yvjIUvyr13yJnDzkK6uon4BjHYuHy3EG0c2Z9jEhFk56w==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.32.0", + "@typescript-eslint/types": "4.32.0", + "@typescript-eslint/typescript-estree": "4.32.0", + "debug": "^4.3.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.32.0.tgz", + "integrity": "sha512-DK+fMSHdM216C0OM/KR1lHXjP1CNtVIhJ54kQxfOE6x8UGFAjha8cXgDMBEIYS2XCYjjCtvTkjQYwL3uvGOo0w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.32.0", + "@typescript-eslint/visitor-keys": "4.32.0" + } + }, + "@typescript-eslint/types": { + "version": "4.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.32.0.tgz", + "integrity": "sha512-LE7Z7BAv0E2UvqzogssGf1x7GPpUalgG07nGCBYb1oK4mFsOiFC/VrSMKbZQzFJdN2JL5XYmsx7C7FX9p9ns0w==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.32.0.tgz", + "integrity": "sha512-tRYCgJ3g1UjMw1cGG8Yn1KzOzNlQ6u1h9AmEtPhb5V5a1TmiHWcRyF/Ic+91M4f43QeChyYlVTcf3DvDTZR9vw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.32.0", + "@typescript-eslint/visitor-keys": "4.32.0", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.32.0.tgz", + "integrity": "sha512-e7NE0qz8W+atzv3Cy9qaQ7BTLwWsm084Z0c4nIO2l3Bp6u9WIgdqCgyPyV5oSPDMIW3b20H59OOCmVk3jw3Ptw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.32.0", + "eslint-visitor-keys": "^2.0.0" + } + }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -3225,6 +3406,11 @@ "css-tree": "^1.1.2" } }, + "csstype": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz", + "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==" + }, "cz-conventional-changelog": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", @@ -8272,6 +8458,15 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -8303,6 +8498,12 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz", + "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==", + "dev": true + }, "uglify-js": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", diff --git a/package.json b/package.json index 6becac0..c4b0477 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,8 @@ "license": "ISC", "private": true, "dependencies": { + "@types/react": "^17.0.26", + "@types/react-dom": "^17.0.9", "react": "^17.0.2", "react-dom": "^17.0.2" }, @@ -21,8 +23,11 @@ "@babel/core": "^7.15.5", "@babel/preset-env": "^7.15.6", "@babel/preset-react": "^7.14.5", + "@babel/preset-typescript": "^7.15.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.1", "@svgr/webpack": "^5.5.0", + "@typescript-eslint/eslint-plugin": "^4.32.0", + "@typescript-eslint/parser": "^4.32.0", "babel-loader": "^8.2.2", "circular-dependency-plugin": "^5.2.2", "clean-terminal-webpack-plugin": "^3.0.0", @@ -43,6 +48,7 @@ "standard-version": "^9.3.1", "style-loader": "^3.3.0", "terser-webpack-plugin": "^5.2.4", + "typescript": "^4.4.3", "webpack": "^5.56.0", "webpack-cli": "^4.8.0", "webpack-dev-server": "^4.3.0", diff --git a/tsconfig.json b/tsconfig.json index 275cdca..09054a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,38 @@ { - "compilerOptions": { - "allowJs": true, - "noEmit": true, - "baseUrl": ".", - "paths": { - "@styles/*": [ - "src/styles/*" - ], - "@assets/*": [ - "src/assets/*" - ] + "compilerOptions": { + "allowJs": true, + "noEmit": true, + "baseUrl": ".", + "paths": { + "@styles/*": [ + "src/styles/*" + ], + "@assets/*": [ + "src/assets/*" + ] + }, + "module": "ESNext", + "target": "ES6", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "sourceMap": true, + "jsx": "preserve", + "moduleResolution": "node", + "skipLibCheck": true, + "esModuleInterop": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noFallthroughCasesInSwitch": true, + "isolatedModules": true }, - "module": "ESNext", - "target": "ES6" - }, - "include": [ - "src" - ] + "include": [ + "src", + "index.d.ts" + ] } \ No newline at end of file diff --git a/webpack.common.js b/webpack.common.js index 538f89d..da1bb61 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -24,7 +24,7 @@ module.exports = { module: { rules: [ { - test: /\.(jsx|js)$/, + test: wmConfig.babel.testFilesRegex, exclude: /node_modules/, include: path.resolve(__dirname, wmConfig.sourceDir), use: [{ diff --git a/webpack.dev.js b/webpack.dev.js index f47d0f5..04c606c 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -14,7 +14,7 @@ const o1 = mergeWithRules(use_options_rule)(webpackCommonConfig, { module: { rules: [ { - test: /\.(jsx|js)$/, + test: wmConfig.babel.testFilesRegex, use: [{ loader: 'babel-loader', options: { diff --git a/wm-config.js b/wm-config.js index 3a4956d..eaa2f57 100644 --- a/wm-config.js +++ b/wm-config.js @@ -9,6 +9,15 @@ const clientPort = 3000 const devHttpsMode = false const hotModuleReload = true const outputESModule = true +const typescript = false +const entryFilenameJs = "index.js" +const entryFilenameTs = "index.tsx" +/** + * if no extenstion is present in module path then following extentions will be tried to resolve the module as a file. + * https://webpack.js.org/concepts/module-resolution/#module-paths + * https://stackoverflow.com/questions/34678314/webpack-cant-find-module-if-file-named-jsx + */ +const extensions = ['.tsx', '.ts', "jsx", '.js'] const browserslist = { "production": [ @@ -26,19 +35,22 @@ const browserslist = { /************************************************************************************************* */ const wmConfig = { + typescript, outputDir: "build", sourceDir: "src", publicDir: "public", - assetsDirInsideOutputDir: "assets", + assetsDirInsideOutputDir: "assets", // Eg: if value is "assets" & outputDir is "build" then folder will be "build/assets" publicDirHtmlFileName: "index.html", outputDirHtmlFileName: "index.html", outputDirFavicomFileName: "favicon.ico", + entryFilenameJs, + entryFilenameTs, webpack: { - entryFilename: "index.js", + entryFilename: typescript ? entryFilenameTs : entryFilenameJs, inlineAssetMaxSize: 6 * 1024, // in Bytes resolve: { alias: getWebpackAliasFromTsConfig(tsConfig), - extensions: ["jsx", '.js'], + extensions, }, outputESModule, // ouput ECMAScript module syntax whenever possible. generateIntialVendorChunk: true, @@ -79,6 +91,7 @@ const wmConfig = { environmentVariablesInApp: [], // strings, add env variables to be available inside web application as process.env.[VAR] }, babel: { + testFilesRegex: new RegExp(`\\.(${extensions.map(v => v.slice(1)).join("|")})$`), getBabelLoaderDefaultOptions: (mode = "production") => ({ cacheDirectory: true, cacheCompression: false, @@ -96,8 +109,9 @@ const wmConfig = { modules: outputESModule ? false : "auto", bugfixes: true } - ] - ] + ], + typescript && "@babel/preset-typescript" + ].filter(Boolean) }) } }