Skip to content

Commit 3bd5339

Browse files
committed
feat(cli): integrate Nx with CLI application
- Add project.json with build, serve, test, and lint targets - Support both OSS and Bit configurations via Nx configurations - Maintain backward compatibility with existing npm build scripts - Update webpack configs to work with both Nx and direct webpack CLI calls - Enable nx build cli --configuration=[oss|oss-dev|bit|bit-dev] commands - Enable nx serve cli for development workflow with watch mode - Preserve all existing npm run build:* commands for compatibility
1 parent 9aa2e2d commit 3bd5339

File tree

9 files changed

+16406
-12147
lines changed

9 files changed

+16406
-12147
lines changed

.github/renovate.json5

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
"@nx/eslint",
148148
"@nx/jest",
149149
"@nx/js",
150+
"@nx/webpack",
150151
"@types/chrome",
151152
"@types/firefox-webext-browser",
152153
"@types/glob",

apps/cli/project.json

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
3+
"name": "cli",
4+
"projectType": "application",
5+
"sourceRoot": "apps/cli/src",
6+
"tags": ["scope:cli", "type:app"],
7+
"targets": {
8+
"build": {
9+
"executor": "@nx/webpack:webpack",
10+
"outputs": ["{options.outputPath}"],
11+
"defaultConfiguration": "oss",
12+
"options": {
13+
"outputPath": "dist/apps/cli",
14+
"webpackConfig": "apps/cli/webpack.nx.config.js",
15+
"tsConfig": "apps/cli/tsconfig.json",
16+
"main": "apps/cli/src/bw.ts",
17+
"target": "node",
18+
"compiler": "tsc"
19+
},
20+
"configurations": {
21+
"oss": {
22+
"mode": "production"
23+
},
24+
"oss-dev": {
25+
"mode": "development"
26+
},
27+
"bit": {
28+
"mode": "production",
29+
"webpackConfig": "bitwarden_license/bit-cli/webpack.config.js",
30+
"main": "bitwarden_license/bit-cli/src/bw.ts",
31+
"tsConfig": "bitwarden_license/bit-cli/tsconfig.json"
32+
},
33+
"bit-dev": {
34+
"mode": "development",
35+
"webpackConfig": "bitwarden_license/bit-cli/webpack.config.js",
36+
"main": "bitwarden_license/bit-cli/src/bw.ts",
37+
"tsConfig": "bitwarden_license/bit-cli/tsconfig.json"
38+
}
39+
}
40+
},
41+
"serve": {
42+
"executor": "@nx/webpack:webpack",
43+
"defaultConfiguration": "oss-dev",
44+
"options": {
45+
"outputPath": "dist/apps/cli",
46+
"webpackConfig": "apps/cli/webpack.nx.config.js",
47+
"tsConfig": "apps/cli/tsconfig.json",
48+
"main": "apps/cli/src/bw.ts",
49+
"target": "node",
50+
"compiler": "tsc",
51+
"watch": true
52+
},
53+
"configurations": {
54+
"oss-dev": {
55+
"mode": "development"
56+
},
57+
"bit-dev": {
58+
"mode": "development",
59+
"webpackConfig": "bitwarden_license/bit-cli/webpack.config.js",
60+
"main": "bitwarden_license/bit-cli/src/bw.ts",
61+
"tsConfig": "bitwarden_license/bit-cli/tsconfig.json"
62+
}
63+
}
64+
},
65+
"test": {
66+
"executor": "@nx/jest:jest",
67+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
68+
"options": {
69+
"jestConfig": "apps/cli/jest.config.js"
70+
}
71+
},
72+
"lint": {
73+
"executor": "@nx/eslint:lint",
74+
"outputs": ["{options.outputFile}"],
75+
"options": {
76+
"lintFilePatterns": ["apps/cli/**/*.ts"]
77+
}
78+
}
79+
}
80+
}

apps/cli/webpack.config.js

Lines changed: 2 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,2 @@
1-
const path = require("path");
2-
const webpack = require("webpack");
3-
const CopyWebpackPlugin = require("copy-webpack-plugin");
4-
const nodeExternals = require("webpack-node-externals");
5-
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
6-
const config = require("./config/config");
7-
8-
if (process.env.NODE_ENV == null) {
9-
process.env.NODE_ENV = "development";
10-
}
11-
const ENV = (process.env.ENV = process.env.NODE_ENV);
12-
13-
const envConfig = config.load(ENV);
14-
config.log(envConfig);
15-
16-
const moduleRules = [
17-
{
18-
test: /\.ts$/,
19-
use: "ts-loader",
20-
exclude: path.resolve(__dirname, "node_modules"),
21-
},
22-
];
23-
24-
const plugins = [
25-
new CopyWebpackPlugin({
26-
patterns: [{ from: "./src/locales", to: "locales" }],
27-
}),
28-
new webpack.DefinePlugin({
29-
"process.env.BWCLI_ENV": JSON.stringify(ENV),
30-
}),
31-
new webpack.BannerPlugin({
32-
banner: "#!/usr/bin/env node",
33-
raw: true,
34-
}),
35-
new webpack.IgnorePlugin({
36-
resourceRegExp: /^encoding$/,
37-
contextRegExp: /node-fetch/,
38-
}),
39-
new webpack.EnvironmentPlugin({
40-
ENV: ENV,
41-
BWCLI_ENV: ENV,
42-
FLAGS: envConfig.flags,
43-
DEV_FLAGS: envConfig.devFlags,
44-
}),
45-
new webpack.IgnorePlugin({
46-
resourceRegExp: /canvas/,
47-
contextRegExp: /jsdom$/,
48-
}),
49-
];
50-
51-
const webpackConfig = {
52-
mode: ENV,
53-
target: "node",
54-
devtool: ENV === "development" ? "eval-source-map" : "source-map",
55-
node: {
56-
__dirname: false,
57-
__filename: false,
58-
},
59-
entry: {
60-
bw: "./src/bw.ts",
61-
},
62-
optimization: {
63-
minimize: false,
64-
},
65-
resolve: {
66-
extensions: [".ts", ".js"],
67-
symlinks: false,
68-
modules: [path.resolve("../../node_modules")],
69-
plugins: [new TsconfigPathsPlugin({ configFile: "./tsconfig.json" })],
70-
},
71-
output: {
72-
filename: "[name].js",
73-
path: path.resolve(__dirname, "build"),
74-
clean: true,
75-
},
76-
module: { rules: moduleRules },
77-
plugins: plugins,
78-
externals: [
79-
nodeExternals({
80-
modulesDir: "../../node_modules",
81-
allowlist: [/@bitwarden/],
82-
}),
83-
],
84-
experiments: {
85-
asyncWebAssembly: true,
86-
},
87-
};
88-
89-
module.exports = webpackConfig;
1+
// For backward compatibility with existing npm scripts
2+
module.exports = require("./webpack.npm.config.js");

apps/cli/webpack.npm.config.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const path = require("path");
2+
const { getSharedConfig } = require("./webpack.shared");
3+
4+
// Original npm/webpack CLI logic
5+
if (process.env.NODE_ENV == null) {
6+
process.env.NODE_ENV = "development";
7+
}
8+
const ENV = (process.env.ENV = process.env.NODE_ENV);
9+
const mode = ENV;
10+
11+
// npm-specific path configuration
12+
const options = {
13+
env: ENV,
14+
mode: mode,
15+
entryPoint: "./src/bw.ts",
16+
outputPath: path.resolve(__dirname, "build"),
17+
modulesPath: [path.resolve("../../node_modules")],
18+
tsconfigPath: "./tsconfig.json",
19+
localesPath: "./src/locales",
20+
externalsModulesDir: "../../node_modules",
21+
};
22+
23+
module.exports = getSharedConfig(options);

apps/cli/webpack.nx.config.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const path = require("path");
2+
const { getSharedConfig } = require("./webpack.shared");
3+
4+
module.exports = (webpackConfig, context) => {
5+
// Set environment based on context mode
6+
const mode = context.options.mode || "development";
7+
if (process.env.NODE_ENV == null) {
8+
process.env.NODE_ENV = mode;
9+
}
10+
const ENV = (process.env.ENV = process.env.NODE_ENV);
11+
12+
// Nx-specific path configuration
13+
const options = {
14+
env: ENV,
15+
mode: mode,
16+
entryPoint: context.options.main || "apps/cli/src/bw.ts",
17+
outputPath: path.resolve(context.context.root, context.options.outputPath),
18+
modulesPath: [path.resolve("node_modules")],
19+
tsconfigPath: "tsconfig.base.json",
20+
localesPath: "apps/cli/src/locales",
21+
externalsModulesDir: "node_modules",
22+
};
23+
24+
return getSharedConfig(options);
25+
};

apps/cli/webpack.shared.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
const path = require("path");
2+
const webpack = require("webpack");
3+
const CopyWebpackPlugin = require("copy-webpack-plugin");
4+
const nodeExternals = require("webpack-node-externals");
5+
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
6+
const config = require("./config/config");
7+
8+
const getSharedConfig = (options) => {
9+
const {
10+
env,
11+
mode,
12+
entryPoint,
13+
outputPath,
14+
modulesPath,
15+
tsconfigPath,
16+
localesPath,
17+
externalsModulesDir,
18+
} = options;
19+
20+
const envConfig = config.load(env);
21+
config.log(envConfig);
22+
23+
return {
24+
mode: mode,
25+
target: "node",
26+
devtool: env === "development" ? "eval-source-map" : "source-map",
27+
node: {
28+
__dirname: false,
29+
__filename: false,
30+
},
31+
entry: {
32+
bw: entryPoint,
33+
},
34+
optimization: {
35+
minimize: false,
36+
},
37+
resolve: {
38+
extensions: [".ts", ".js"],
39+
symlinks: false,
40+
modules: modulesPath,
41+
plugins: [new TsconfigPathsPlugin({ configFile: tsconfigPath })],
42+
},
43+
output: {
44+
filename: "[name].js",
45+
path: outputPath,
46+
clean: true,
47+
},
48+
module: { rules: getModuleRules() },
49+
plugins: getPlugins(env, envConfig, localesPath),
50+
externals: getExternals(externalsModulesDir),
51+
experiments: {
52+
asyncWebAssembly: true,
53+
},
54+
};
55+
};
56+
57+
const getModuleRules = () => {
58+
return [
59+
{
60+
test: /\.ts$/,
61+
use: "ts-loader",
62+
exclude: path.resolve(__dirname, "node_modules"),
63+
},
64+
];
65+
};
66+
67+
const getPlugins = (env, envConfig, localesPath) => {
68+
return [
69+
new CopyWebpackPlugin({
70+
patterns: [{ from: localesPath, to: "locales" }],
71+
}),
72+
new webpack.DefinePlugin({
73+
"process.env.BWCLI_ENV": JSON.stringify(env),
74+
}),
75+
new webpack.BannerPlugin({
76+
banner: "#!/usr/bin/env node",
77+
raw: true,
78+
}),
79+
new webpack.IgnorePlugin({
80+
resourceRegExp: /^encoding$/,
81+
contextRegExp: /node-fetch/,
82+
}),
83+
new webpack.EnvironmentPlugin({
84+
ENV: env,
85+
BWCLI_ENV: env,
86+
FLAGS: envConfig.flags,
87+
DEV_FLAGS: envConfig.devFlags,
88+
}),
89+
new webpack.IgnorePlugin({
90+
resourceRegExp: /canvas/,
91+
contextRegExp: /jsdom$/,
92+
}),
93+
];
94+
};
95+
96+
const getExternals = (externalsModulesDir) => {
97+
return [
98+
nodeExternals({
99+
modulesDir: externalsModulesDir,
100+
allowlist: [/@bitwarden/],
101+
}),
102+
];
103+
};
104+
105+
module.exports = {
106+
getSharedConfig,
107+
getModuleRules,
108+
getPlugins,
109+
getExternals,
110+
};
Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,46 @@
11
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
22

3-
// Re-use the OSS CLI webpack config
4-
const webpackConfig = require("../../apps/cli/webpack.config");
3+
module.exports = (webpackConfig, context) => {
4+
// Check if this is being called by Nx or directly by webpack CLI
5+
const isNxBuild = !!(context && context.options);
56

6-
// Update paths to use the bit-cli entrypoint and tsconfig
7-
webpackConfig.entry = { bw: "../../bitwarden_license/bit-cli/src/bw.ts" };
8-
webpackConfig.resolve.plugins = [
9-
new TsconfigPathsPlugin({ configFile: "../../bitwarden_license/bit-cli/tsconfig.json" }),
10-
];
7+
let config;
118

12-
module.exports = webpackConfig;
9+
if (isNxBuild) {
10+
// Use Nx configuration as base
11+
const nxConfig = require("../../apps/cli/webpack.nx.config.js");
12+
config = nxConfig(webpackConfig, context);
13+
14+
// Apply bit-cli specific modifications for Nx builds
15+
config.entry = { bw: context.options.main || "bitwarden_license/bit-cli/src/bw.ts" };
16+
config.resolve.plugins = [new TsconfigPathsPlugin({ configFile: "tsconfig.base.json" })];
17+
18+
// Update the locales path for bit-cli in Nx context
19+
const copyPlugin = config.plugins.find(
20+
(plugin) => plugin.constructor.name === "CopyWebpackPlugin",
21+
);
22+
if (copyPlugin) {
23+
copyPlugin.patterns = [{ from: "bitwarden_license/bit-cli/src/locales", to: "locales" }];
24+
}
25+
} else {
26+
// Use npm configuration as base
27+
const npmConfig = require("../../apps/cli/webpack.npm.config.js");
28+
config = { ...npmConfig };
29+
30+
// Apply bit-cli specific modifications for npm builds
31+
config.entry = { bw: "../../bitwarden_license/bit-cli/src/bw.ts" };
32+
config.resolve.plugins = [
33+
new TsconfigPathsPlugin({ configFile: "../../bitwarden_license/bit-cli/tsconfig.json" }),
34+
];
35+
36+
// Update the locales path for bit-cli (relative to bit-cli directory)
37+
const copyPlugin = config.plugins.find(
38+
(plugin) => plugin.constructor.name === "CopyWebpackPlugin",
39+
);
40+
if (copyPlugin) {
41+
copyPlugin.patterns = [{ from: "./src/locales", to: "locales" }];
42+
}
43+
}
44+
45+
return config;
46+
};

0 commit comments

Comments
 (0)