From a817ed17a20b3ed927185b9b96caabce3f9465b1 Mon Sep 17 00:00:00 2001 From: Isidor Nygren Date: Thu, 21 Apr 2022 16:23:37 +0200 Subject: [PATCH] Add basic typescript integration --- .babelrc.json | 1 + .eslintrc.json | 4 ++-- package.json | 9 +++++++-- src/{app.jsx => app.tsx} | 12 ++++++++---- src/{index.js => index.ts} | 2 +- src/types/cockpit.ts | 5 +++++ tsconfig.json | 16 ++++++++++++++++ webpack.config.js | 9 ++++++--- 8 files changed, 46 insertions(+), 12 deletions(-) rename src/{app.jsx => app.tsx} (84%) rename src/{index.js => index.ts} (97%) create mode 100644 src/types/cockpit.ts create mode 100644 tsconfig.json diff --git a/.babelrc.json b/.babelrc.json index dfe57f2..f1d8b49 100644 --- a/.babelrc.json +++ b/.babelrc.json @@ -9,6 +9,7 @@ "opera": "44" } }], + "@babel/preset-typescript", "@babel/preset-react" ] } diff --git a/.eslintrc.json b/.eslintrc.json index f2b0ea2..3b9b716 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,7 @@ "browser": true, "es6": true }, - "extends": ["eslint:recommended", "standard", "standard-jsx", "react-app"], + "extends": ["eslint:recommended", "standard", "standard-jsx", "react-app", "plugin:@typescript-eslint/recommended"], "parser": "@babel/eslint-parser", "parserOptions": { "ecmaVersion": "7", @@ -13,7 +13,7 @@ }, "sourceType": "module" }, - "plugins": ["flowtype", "react", "react-hooks"], + "plugins": ["flowtype", "react", "react-hooks", "@typescript-eslint"], "rules": { "indent": ["error", 4, { diff --git a/package.json b/package.json index 59d6332..58df1dd 100644 --- a/package.json +++ b/package.json @@ -8,14 +8,18 @@ "scripts": { "watch": "webpack --watch --progress", "build": "webpack", - "eslint": "eslint --ext .js --ext .jsx src/", - "eslint:fix": "eslint --fix --ext .js --ext .jsx src/" + "eslint": "eslint --ext .js --ext .jsx --ext .ts --ext .tsx src/", + "eslint:fix": "eslint --fix --ext .js --ext .jsx --ext .ts --ext .tsx src/" }, "devDependencies": { "@babel/core": "^7.5.4", "@babel/eslint-parser": "^7.17.0", "@babel/preset-env": "^7.5.4", "@babel/preset-react": "^7.0.0", + "@babel/preset-typescript": "^7.16.7", + "@types/react": "^17.0.44", + "@types/react-dom": "^17.0.15", + "@typescript-eslint/eslint-plugin": "^5.20.0", "babel-loader": "^8.0.6", "chrome-remote-interface": "^0.31.0", "compression-webpack-plugin": "^9.0.0", @@ -33,6 +37,7 @@ "eslint-plugin-react": "^7.29.4", "eslint-plugin-react-hooks": "^4.4.0", "eslint-webpack-plugin": "^3.1.1", + "fork-ts-checker-webpack-plugin": "^7.2.6", "htmlparser": "^1.7.7", "jed": "^1.1.1", "mini-css-extract-plugin": "^2.5.3", diff --git a/src/app.jsx b/src/app.tsx similarity index 84% rename from src/app.jsx rename to src/app.tsx index c88d25e..7920708 100644 --- a/src/app.jsx +++ b/src/app.tsx @@ -21,14 +21,18 @@ import cockpit from 'cockpit'; import React from 'react'; import { Alert, Card, CardTitle, CardBody } from '@patternfly/react-core'; +interface ApplicationState { + hostname: string; +} + const _ = cockpit.gettext; -export class Application extends React.Component { - constructor() { - super(); +export class Application extends React.Component { + constructor(props: unknown) { + super(props); this.state = { hostname: _("Unknown") }; - cockpit.file('/etc/hostname').watch(content => { + cockpit.file('/etc/hostname').watch((content: string) => { this.setState({ hostname: content.trim() }); }); } diff --git a/src/index.js b/src/index.ts similarity index 97% rename from src/index.js rename to src/index.ts index a0e5c45..540b226 100644 --- a/src/index.js +++ b/src/index.ts @@ -21,7 +21,7 @@ import "./lib/patternfly/patternfly-4-cockpit.scss"; import React from 'react'; import ReactDOM from 'react-dom'; -import { Application } from './app.jsx'; +import { Application } from './app'; /* * PF4 overrides need to come after the JSX components imports because * these are importing CSS stylesheets that we are overriding diff --git a/src/types/cockpit.ts b/src/types/cockpit.ts new file mode 100644 index 0000000..4f3e6ec --- /dev/null +++ b/src/types/cockpit.ts @@ -0,0 +1,5 @@ +declare module 'cockpit' { + export function gettext(prop: string): string; + export function file(prop: any): any; + export function format(...prop:any): any; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..aad2ff7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "es2015", + "module": "commonjs", + "lib": ["dom", "es2017"], + "strict": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "moduleResolution": "node", + "noEmitOnError": true, + "esModuleInterop": true, + "jsx": "react", + "types": [ "src/types" ] + } + } + \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 63e5dc6..cd49a7c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -9,6 +9,7 @@ const CompressionPlugin = require("compression-webpack-plugin"); const ESLintPlugin = require('eslint-webpack-plugin'); const CockpitPoPlugin = require("./src/lib/cockpit-po-plugin"); const CockpitRsyncPlugin = require("./src/lib/cockpit-rsync-plugin"); +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); /* A standard nodejs and webpack pattern */ const production = process.env.NODE_ENV === 'production'; @@ -30,10 +31,11 @@ const plugins = [ new extract({filename: "[name].css"}), new CockpitPoPlugin(), new CockpitRsyncPlugin({dest: packageJson.name}), + new ForkTsCheckerWebpackPlugin() ]; if (eslint) { - plugins.push(new ESLintPlugin({ extensions: ["js", "jsx"], failOnWarning: true, })); + plugins.push(new ESLintPlugin({ extensions: ["js", "jsx", "ts", "tsx"], failOnWarning: true, })); } /* Only minimize when in production mode */ @@ -49,6 +51,7 @@ module.exports = { resolve: { modules: [ "node_modules", path.resolve(__dirname, 'src/lib') ], alias: { 'font-awesome': 'font-awesome-sass/assets/stylesheets' }, + extensions: ['.tsx', '.ts', '.js', '.jsx'] }, resolveLoader: { modules: [ "node_modules", path.resolve(__dirname, 'src/lib') ], @@ -57,7 +60,7 @@ module.exports = { ignored: /node_modules/, }, entry: { - index: "./src/index.js", + index: "./src/index.ts", }, // cockpit.js gets included via