diff --git a/superset-extensions-cli/src/superset_extensions_cli/cli.py b/superset-extensions-cli/src/superset_extensions_cli/cli.py index 06ca4508f11..294fff1f547 100644 --- a/superset-extensions-cli/src/superset_extensions_cli/cli.py +++ b/superset-extensions-cli/src/superset_extensions_cli/cli.py @@ -441,24 +441,42 @@ def init() -> None: (target_dir / "extension.json").write_text(extension_json) click.secho("✅ Created extension.json", fg="green") - # Copy frontend template + # Initialize frontend files if include_frontend: frontend_dir = target_dir / "frontend" frontend_dir.mkdir() + frontend_src_dir = frontend_dir / "src" + frontend_src_dir.mkdir() - # package.json + # frontend files package_json = env.get_template("frontend/package.json.j2").render(ctx) (frontend_dir / "package.json").write_text(package_json) + webpack_config = env.get_template("frontend/webpack.config.js.j2").render(ctx) + (frontend_dir / "webpack.config.js").write_text(webpack_config) + tsconfig_json = env.get_template("frontend/tsconfig.json.j2").render(ctx) + (frontend_dir / "tsconfig.json").write_text(tsconfig_json) + index_tsx = env.get_template("frontend/src/index.tsx.j2").render(ctx) + (frontend_src_dir / "index.tsx").write_text(index_tsx) click.secho("✅ Created frontend folder structure", fg="green") - # Copy backend template + # Initialize backend files if include_backend: backend_dir = target_dir / "backend" backend_dir.mkdir() + backend_src_dir = backend_dir / "src" + backend_src_dir.mkdir() + backend_src_package_dir = backend_src_dir / id_ + backend_src_package_dir.mkdir() - # pyproject.toml + # backend files pyproject_toml = env.get_template("backend/pyproject.toml.j2").render(ctx) (backend_dir / "pyproject.toml").write_text(pyproject_toml) + init_py = env.get_template("backend/src/package/__init__.py.j2").render(ctx) + (backend_src_package_dir / "__init__.py").write_text(init_py) + entrypoint_py = env.get_template("backend/src/package/entrypoint.py.j2").render( + ctx + ) + (backend_src_package_dir / "entrypoint.py").write_text(entrypoint_py) click.secho("✅ Created backend folder structure", fg="green") diff --git a/superset-extensions-cli/src/superset_extensions_cli/templates/backend/src/package/__init__.py.j2 b/superset-extensions-cli/src/superset_extensions_cli/templates/backend/src/package/__init__.py.j2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/superset-extensions-cli/src/superset_extensions_cli/templates/backend/src/package/entrypoint.py.j2 b/superset-extensions-cli/src/superset_extensions_cli/templates/backend/src/package/entrypoint.py.j2 new file mode 100644 index 00000000000..2ff158bf997 --- /dev/null +++ b/superset-extensions-cli/src/superset_extensions_cli/templates/backend/src/package/entrypoint.py.j2 @@ -0,0 +1 @@ +print("{{ name }} extension registered") diff --git a/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/package.json.j2 b/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/package.json.j2 index 6ad06143bee..971902917f5 100644 --- a/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/package.json.j2 +++ b/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/package.json.j2 @@ -14,7 +14,7 @@ "license": "{{ license }}", "description": "", "peerDependencies": { - "@apache-superset/core": "file:../../../superset-frontend/packages/superset-core", + "@apache-superset/core": "*", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/src/index.tsx.j2 b/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/src/index.tsx.j2 new file mode 100644 index 00000000000..b9a6266216d --- /dev/null +++ b/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/src/index.tsx.j2 @@ -0,0 +1,13 @@ +import React from "react"; +import { core } from "@apache-superset/core"; + +export const activate = (context: core.ExtensionContext) => { + context.disposables.push( + core.registerViewProvider("{{ id }}.example", () =>

{{ name }}

) + ); + console.log("{{ name }} extension activated"); +}; + +export const deactivate = () => { + console.log("{{ name }} extension deactivated"); +}; diff --git a/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/tsconfig.json.j2 b/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/tsconfig.json.j2 new file mode 100644 index 00000000000..ed813aa9443 --- /dev/null +++ b/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/tsconfig.json.j2 @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "esnext", + "moduleResolution": "node10", + "jsx": "react", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src"] +} diff --git a/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/webpack.config.js.j2 b/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/webpack.config.js.j2 new file mode 100644 index 00000000000..25f1b5c0be6 --- /dev/null +++ b/superset-extensions-cli/src/superset_extensions_cli/templates/frontend/webpack.config.js.j2 @@ -0,0 +1,67 @@ +const path = require("path"); +const { ModuleFederationPlugin } = require("webpack").container; +const packageConfig = require("./package"); + +module.exports = (env, argv) => { + const isProd = argv.mode === "production"; + + return { + entry: isProd ? {} : "./src/index.tsx", + mode: isProd ? "production" : "development", + devServer: { + port: 3000, + headers: { + "Access-Control-Allow-Origin": "*", + }, + }, + output: { + clean: true, + filename: isProd ? undefined : "[name].[contenthash].js", + chunkFilename: "[name].[contenthash].js", + path: path.resolve(__dirname, "dist"), + publicPath: `/api/v1/extensions/${packageConfig.name}/`, + }, + resolve: { + extensions: [".ts", ".tsx", ".js", ".jsx"], + }, + externalsType: "window", + externals: { + "@apache-superset/core": "superset", + }, + module: { + rules: [ + { + test: /\.tsx?$/, + use: "ts-loader", + exclude: /node_modules/, + }, + ], + }, + plugins: [ + new ModuleFederationPlugin({ + name: "{{ id }}", + filename: "remoteEntry.[contenthash].js", + exposes: { + "./index": "./src/index.tsx", + }, + shared: { + react: { + singleton: true, + requiredVersion: packageConfig.peerDependencies.react, + import: false, + }, + "react-dom": { + singleton: true, + requiredVersion: packageConfig.peerDependencies["react-dom"], + import: false, + }, + antd: { + singleton: true, + requiredVersion: packageConfig.peerDependencies["antd"], + import: false, + }, + }, + }), + ], + }; +};