diff --git a/generators/client/command.ts b/generators/client/command.ts
index b52503537712..272bbd485fc5 100644
--- a/generators/client/command.ts
+++ b/generators/client/command.ts
@@ -63,6 +63,14 @@ const command = {
],
scope: 'storage',
},
+ clientBundler: {
+ cli: {
+ type: String,
+ hide: true,
+ },
+ choices: ['webpack', 'rsbuild', 'vite'],
+ scope: 'storage',
+ },
microfrontend: {
description: 'Enable microfrontend support',
cli: {
diff --git a/generators/client/files-common.ts b/generators/client/files-common.ts
index 5f975616225d..6db7ddb69eac 100644
--- a/generators/client/files-common.ts
+++ b/generators/client/files-common.ts
@@ -25,7 +25,7 @@ export const files = {
templates: ['README.md.jhi.client', '.prettierignore.jhi.client'],
},
clientRootTemplatesBlock({
- condition: generator => generator.microfrontend && (generator.clientFrameworkVue || generator.clientFrameworkReact),
+ condition: generator => generator.microfrontend && generator.clientFrameworkReact,
templates: ['webpack/webpack.microfrontend.js.jhi'],
}),
{
diff --git a/generators/client/generator.ts b/generators/client/generator.ts
index e42da8e2b3d9..87e12d052aa5 100644
--- a/generators/client/generator.ts
+++ b/generators/client/generator.ts
@@ -252,9 +252,9 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator {
source.addWebpackConfig({
config: `${conditional}require('./webpack.microfrontend')(config, options, targetOptions)`,
});
- } else if (application.clientFrameworkVue || application.clientFrameworkReact) {
+ } else if (application.clientFrameworkReact) {
source.addWebpackConfig({ config: "require('./webpack.microfrontend')({ serve: options.env.WEBPACK_SERVE })" });
- } else {
+ } else if (!application.clientFrameworkVue) {
throw new Error(`Client framework ${application.clientFramework} doesn't support microfrontends`);
}
},
diff --git a/generators/gradle/generators/node-gradle/templates/buildSrc/src/main/groovy/jhipster.node-gradle-conventions.gradle.ejs b/generators/gradle/generators/node-gradle/templates/buildSrc/src/main/groovy/jhipster.node-gradle-conventions.gradle.ejs
index 76180541fd09..dde9de0e4f7f 100644
--- a/generators/gradle/generators/node-gradle/templates/buildSrc/src/main/groovy/jhipster.node-gradle-conventions.gradle.ejs
+++ b/generators/gradle/generators/node-gradle/templates/buildSrc/src/main/groovy/jhipster.node-gradle-conventions.gradle.ejs
@@ -68,10 +68,8 @@ task webapp_test(type: NpmTask) {
.withPathSensitivity(PathSensitivity.RELATIVE)
<%_ if (microfrontend) { _%>
- def webpackDevFiles = fileTree("<%= CLIENT_WEBPACK_DIR %>")
- webpackDevFiles.exclude("webpack.prod.js")
- inputs.files(webpackDevFiles)
- .withPropertyName("webpack-dir")
+ inputs.files('rsbuild.config.ts', 'rsbuild.module-federation.config.ts')
+ .withPropertyName("rsbuild")
.withPathSensitivity(PathSensitivity.RELATIVE)
<%_ } else { _%>
diff --git a/generators/javascript/generators/rsbuild/__snapshots__/generator.spec.ts.snap b/generators/javascript/generators/rsbuild/__snapshots__/generator.spec.ts.snap
new file mode 100644
index 000000000000..f5dfc067cbc8
--- /dev/null
+++ b/generators/javascript/generators/rsbuild/__snapshots__/generator.spec.ts.snap
@@ -0,0 +1,17 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`generator - javascript:rsbuild with defaults options should call source snapshot 1`] = `{}`;
+
+exports[`generator - javascript:rsbuild with defaults options should match files snapshot 1`] = `
+{
+ ".yo-rc.json": {
+ "stateCleared": "modified",
+ },
+ "package.json": {
+ "stateCleared": "modified",
+ },
+ "rsbuild.config.ts.jhi": {
+ "stateCleared": "modified",
+ },
+}
+`;
diff --git a/generators/javascript/generators/rsbuild/command.ts b/generators/javascript/generators/rsbuild/command.ts
new file mode 100644
index 000000000000..de9446fa3118
--- /dev/null
+++ b/generators/javascript/generators/rsbuild/command.ts
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2013-2024 the original author or authors from the JHipster project.
+ *
+ * This file is part of the JHipster project, see https://www.jhipster.tech/
+ * for more information.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import type { JHipsterCommandDefinition } from '../../../../lib/command/types.js';
+
+const command = {
+ configs: {},
+ import: [],
+} as const satisfies JHipsterCommandDefinition;
+
+export default command;
diff --git a/generators/javascript/generators/rsbuild/generator.spec.ts b/generators/javascript/generators/rsbuild/generator.spec.ts
new file mode 100644
index 000000000000..1552e18ce2ae
--- /dev/null
+++ b/generators/javascript/generators/rsbuild/generator.spec.ts
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2013-2024 the original author or authors from the JHipster project.
+ *
+ * This file is part of the JHipster project, see https://www.jhipster.tech/
+ * for more information.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { basename, dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { before, describe, expect, it } from 'esmocha';
+
+import { shouldSupportFeatures, testBlueprintSupport } from '../../../../test/support/tests.js';
+import { defaultHelpers as helpers, result } from '../../../../lib/testing/index.js';
+import Generator from './index.js';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+const generator = `${basename(resolve(__dirname, '../../'))}:${basename(__dirname)}`;
+
+describe(`generator - ${generator}`, () => {
+ shouldSupportFeatures(Generator);
+ describe('blueprint support', () => testBlueprintSupport(generator));
+
+ describe('with defaults options', () => {
+ before(async () => {
+ await helpers.runJHipster(generator).withMockedJHipsterGenerators().withMockedSource().withSharedApplication({}).withJHipsterConfig();
+ });
+
+ it('should match files snapshot', () => {
+ expect(result.getStateSnapshot()).toMatchSnapshot();
+ });
+
+ it('should call source snapshot', () => {
+ expect(result.sourceCallsArg).toMatchSnapshot();
+ });
+
+ it('should compose with generators', () => {
+ expect(result.composedMockedGenerators).toMatchInlineSnapshot(`[]`);
+ });
+ });
+});
diff --git a/generators/javascript/generators/rsbuild/generator.ts b/generators/javascript/generators/rsbuild/generator.ts
new file mode 100644
index 000000000000..8443800a1f6b
--- /dev/null
+++ b/generators/javascript/generators/rsbuild/generator.ts
@@ -0,0 +1,129 @@
+/**
+ * Copyright 2013-2024 the original author or authors from the JHipster project.
+ *
+ * This file is part of the JHipster project, see https://www.jhipster.tech/
+ * for more information.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import BaseGenerator from '../../../../generators/base-application/index.js';
+
+export default class RspackGenerator extends BaseGenerator {
+ constructor(args, options, features) {
+ super(args, options, { queueCommandTasks: true, ...features });
+ }
+
+ async beforeQueue() {
+ if (!this.fromBlueprint) {
+ await this.composeWithBlueprints();
+ }
+
+ if (!this.delegateToBlueprint) {
+ await this.dependsOnBootstrapApplication();
+ }
+ }
+
+ get preparing() {
+ return this.asPreparingTaskGroup({});
+ }
+
+ get [BaseGenerator.PREPARING]() {
+ return this.delegateTasksToBlueprint(() => this.preparing);
+ }
+
+ get postPreparing() {
+ return this.asPostPreparingTaskGroup({});
+ }
+
+ get [BaseGenerator.POST_PREPARING]() {
+ return this.delegateTasksToBlueprint(() => this.postPreparing);
+ }
+
+ get preparingEachEntity() {
+ return this.asPreparingEachEntityTaskGroup({});
+ }
+
+ get [BaseGenerator.PREPARING_EACH_ENTITY]() {
+ return this.delegateTasksToBlueprint(() => this.preparingEachEntity);
+ }
+
+ get preparingEachEntityField() {
+ return this.asPreparingEachEntityFieldTaskGroup({});
+ }
+
+ get [BaseGenerator.PREPARING_EACH_ENTITY_FIELD]() {
+ return this.delegateTasksToBlueprint(() => this.preparingEachEntityField);
+ }
+
+ get preparingEachEntityRelationship() {
+ return this.asPreparingEachEntityRelationshipTaskGroup({});
+ }
+
+ get [BaseGenerator.PREPARING_EACH_ENTITY_RELATIONSHIP]() {
+ return this.delegateTasksToBlueprint(() => this.preparingEachEntityRelationship);
+ }
+
+ get postPreparingEachEntity() {
+ return this.asPostPreparingEachEntityTaskGroup({});
+ }
+
+ get [BaseGenerator.POST_PREPARING_EACH_ENTITY]() {
+ return this.delegateTasksToBlueprint(() => this.postPreparingEachEntity);
+ }
+
+ get default() {
+ return this.asDefaultTaskGroup({});
+ }
+
+ get [BaseGenerator.DEFAULT]() {
+ return this.delegateTasksToBlueprint(() => this.default);
+ }
+
+ get writing() {
+ return this.asWritingTaskGroup({
+ async writeFiles({ application }) {
+ await this.writeFiles({
+ blocks: [{ templates: ['rsbuild.config.ts.jhi'] }],
+ context: application,
+ });
+ },
+ });
+ }
+
+ get [BaseGenerator.WRITING]() {
+ return this.delegateTasksToBlueprint(() => this.writing);
+ }
+
+ get postWriting() {
+ return this.asPostWritingTaskGroup({
+ addScripts({ application }) {
+ this.packageJson.merge({
+ devDependencies: {
+ '@rsbuild/core': 'latest',
+ },
+ scripts: {
+ start: 'rsbuild dev',
+ build: 'rsbuild build',
+ 'webapp:build:dev': `${application.clientPackageManager} run build -- --mode=development`,
+ 'webapp:build:prod': `${application.clientPackageManager} run build -- --mode=production`,
+ 'webapp:dev': `${application.clientPackageManager} run start`,
+ },
+ });
+ },
+ });
+ }
+
+ get [BaseGenerator.POST_WRITING]() {
+ return this.delegateTasksToBlueprint(() => this.postWriting);
+ }
+}
diff --git a/generators/javascript/generators/rsbuild/index.ts b/generators/javascript/generators/rsbuild/index.ts
new file mode 100644
index 000000000000..1cfadd692bb6
--- /dev/null
+++ b/generators/javascript/generators/rsbuild/index.ts
@@ -0,0 +1,20 @@
+/**
+ * Copyright 2013-2024 the original author or authors from the JHipster project.
+ *
+ * This file is part of the JHipster project, see https://www.jhipster.tech/
+ * for more information.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default } from './generator.js';
+export { default as command } from './command.js';
diff --git a/generators/javascript/generators/rsbuild/templates/rsbuild.config.ts.jhi.ejs b/generators/javascript/generators/rsbuild/templates/rsbuild.config.ts.jhi.ejs
new file mode 100644
index 000000000000..e955d62143f6
--- /dev/null
+++ b/generators/javascript/generators/rsbuild/templates/rsbuild.config.ts.jhi.ejs
@@ -0,0 +1,57 @@
+<%#
+ Copyright 2013-2024 the original author or authors from the JHipster project.
+
+ This file is part of the JHipster project, see https://www.jhipster.tech/
+ for more information.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-%>
+<&_
+ // Register sections and max allowed fragments, 0 for unlimited.
+ fragments.registerSections({
+ importsSection: 0,
+ pluginsSection: 0,
+ configSection: 0,
+ });
+_&>
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { defineConfig } from '@rsbuild/core';
+<&- fragments.importsSection() -&>
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+export default defineConfig({
+ root: path.join(__dirname, '<%- this.relativeDir(clientRootDir, clientSrcDir) %>'),
+ output: {
+ cleanDistPath: true,
+ distPath: {
+ root: path.join(__dirname, './<%= this.relativeDir(clientRootDir, clientDistDir) %>'),
+ },
+ },
+ html: {
+ template: './index.html',
+ scriptLoading: 'defer',
+ tags: [
+ {
+ tag: 'base',
+ attrs: { href: '/' },
+ },
+ ],
+ },
+ plugins: [
+<&- fragments.pluginsSection() -&>
+ ],
+<&- fragments.configSection() -&>
+});
diff --git a/generators/maven/generators/frontend-plugin/generator.ts b/generators/maven/generators/frontend-plugin/generator.ts
index bb6b3c2b3811..aa72e866c72b 100644
--- a/generators/maven/generators/frontend-plugin/generator.ts
+++ b/generators/maven/generators/frontend-plugin/generator.ts
@@ -58,7 +58,7 @@ export default class FrontendPluginGenerator extends BaseApplicationGenerator {
} else if (clientFrameworkVue) {
checksumIncludedFiles.push('.postcssrc.js', 'tsconfig.app.json');
if (microfrontend) {
- checksumIncludedFiles.push('webpack/*.*');
+ checksumIncludedFiles.push('rsbuild.config.ts', 'rsbuild.module-federation.config.ts');
} else {
checksumIncludedFiles.push('vite.config.ts');
}
diff --git a/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs
index 5fa690b4919b..6820c134aff3 100644
--- a/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs
+++ b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_imperative.java.ejs
@@ -194,17 +194,15 @@ public class SecurityConfiguration {
<%_ if (!skipClient) { _%>
.requestMatchers(mvc.pattern("/index.html"), mvc.pattern("/*.js"), mvc.pattern("/*.txt"), mvc.pattern("/*.json"), mvc.pattern("/*.map"), mvc.pattern("/*.css")).permitAll()
.requestMatchers(mvc.pattern("/*.ico"), mvc.pattern("/*.png"), mvc.pattern("/*.svg"), mvc.pattern("/*.webapp")).permitAll()
- <%_ if (clientFrameworkVue) { _%>
+ <%_ if (clientBundlerRsbuild) { _%>
+ .requestMatchers(mvc.pattern("/static/**")).permitAll()
+ <%_ } else if (clientBundlerVite) { _%>
.requestMatchers(mvc.pattern("/assets/**")).permitAll()
- <%_ if (microfrontend) { _%>
- .requestMatchers(mvc.pattern("/app/**")).permitAll()
- .requestMatchers(mvc.pattern("/i18n/**")).permitAll()
- <%_ } _%>
<%_ } else { _%>
.requestMatchers(mvc.pattern("/app/**")).permitAll()
.requestMatchers(mvc.pattern("/i18n/**")).permitAll()
- <%_ } _%>
.requestMatchers(mvc.pattern("/content/**")).permitAll()
+ <%_ } _%>
.requestMatchers(mvc.pattern("/swagger-ui/**")).permitAll()
<%_ } _%>
<%_ if (authenticationTypeJwt) { _%>
@@ -227,7 +225,11 @@ public class SecurityConfiguration {
<%_ if (applicationTypeGateway) { _%>
<%_ if (microfrontend) { _%>
// microfrontend resources are loaded by webpack without authentication, they need to be public
+ <%_ if (clientBundlerRsbuild) { _%>
+ .requestMatchers(mvc.pattern("/services/*/static/**")).permitAll()
+ <%_ } _%>
.requestMatchers(mvc.pattern("/services/*/*.js")).permitAll()
+ .requestMatchers(mvc.pattern("/services/*/content/*.js")).permitAll()
.requestMatchers(mvc.pattern("/services/*/*.txt")).permitAll()
.requestMatchers(mvc.pattern("/services/*/*.json")).permitAll()
.requestMatchers(mvc.pattern("/services/*/*.js.map")).permitAll()
diff --git a/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs
index dc987fc12acb..9f79e9ee2f8a 100644
--- a/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs
+++ b/generators/spring-boot/templates/src/main/java/_package_/config/SecurityConfiguration_reactive.java.ejs
@@ -214,19 +214,18 @@ public class SecurityConfiguration {
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.securityMatcher(new NegatedServerWebExchangeMatcher(new OrServerWebExchangeMatcher(
- <%_ if (clientFrameworkVue) { _%>
pathMatchers(
+ <%_ if (clientBundlerRsbuild) { _%>
+ "/static/**",
+ <%_ } else if (clientBundlerVite) { _%>
"/assets/**",
- <%_ if (microfrontend) { _%>
+ <%_ } else { _%>
"/app/**",
"/i18n/**",
"/content/**",
- <%_ } _%>
+ <%_ } _%>
"/swagger-ui/**"
)
- <%_ } else { _%>
- pathMatchers("/app/**", "/i18n/**", "/content/**", "/swagger-ui/**")
- <%_ } _%>
)))
<%_ if (!applicationTypeMicroservice) { _%>
.cors(withDefaults())
@@ -286,7 +285,11 @@ public class SecurityConfiguration {
<%_ if (applicationTypeGateway) { _%>
<%_ if (microfrontend) { _%>
// microfrontend resources are loaded by webpack without authentication, they need to be public
+ <%_ if (clientBundlerRsbuild) { _%>
+ .pathMatchers("/services/*/static/**").permitAll()
+ <%_ } _%>
.pathMatchers("/services/*/*.js").permitAll()
+ .pathMatchers("/services/*/content/*.js").permitAll()
.pathMatchers("/services/*/*.txt").permitAll()
.pathMatchers("/services/*/*.json").permitAll()
.pathMatchers("/services/*/*.js.map").permitAll()
diff --git a/generators/vue/__snapshots__/generator.spec.ts.snap b/generators/vue/__snapshots__/generator.spec.ts.snap
index 81c96d44f772..f73e715083be 100644
--- a/generators/vue/__snapshots__/generator.spec.ts.snap
+++ b/generators/vue/__snapshots__/generator.spec.ts.snap
@@ -1092,9 +1092,6 @@ exports[`generator - vue microservice-jwt-skipUserManagement(false)-withAdminUi(
"clientRoot/src/main/webapp/app/entities/entities-menu.component.ts": {
"stateCleared": "modified",
},
- "clientRoot/src/main/webapp/app/entities/entities-menu.spec.ts": {
- "stateCleared": "modified",
- },
"clientRoot/src/main/webapp/app/entities/entities-menu.vue": {
"stateCleared": "modified",
},
@@ -1395,9 +1392,6 @@ exports[`generator - vue microservice-jwt-skipUserManagement(false)-withAdminUi(
"clientRoot/src/main/webapp/manifest.webapp": {
"stateCleared": "modified",
},
- "clientRoot/src/main/webapp/microfrontends/entities-menu-test.vue": {
- "stateCleared": "modified",
- },
"clientRoot/src/main/webapp/microfrontends/entities-menu.component-test.ts": {
"stateCleared": "modified",
},
@@ -1431,22 +1425,13 @@ exports[`generator - vue microservice-jwt-skipUserManagement(false)-withAdminUi(
"clientRoot/vitest.config.mts": {
"stateCleared": "modified",
},
- "clientRoot/webpack/config.js": {
- "stateCleared": "modified",
- },
- "clientRoot/webpack/vue.utils.js": {
- "stateCleared": "modified",
- },
- "clientRoot/webpack/webpack.common.js": {
- "stateCleared": "modified",
- },
- "clientRoot/webpack/webpack.dev.js": {
+ "package.json": {
"stateCleared": "modified",
},
- "clientRoot/webpack/webpack.microfrontend.js": {
+ "rsbuild.config.ts": {
"stateCleared": "modified",
},
- "clientRoot/webpack/webpack.prod.js": {
+ "rsbuild.module-federation.config.ts": {
"stateCleared": "modified",
},
}
@@ -1478,6 +1463,12 @@ exports[`generator - vue microservice-oauth2-withAdminUi(true)-skipJhipsterDepen
"package.json": {
"stateCleared": "modified",
},
+ "rsbuild.config.ts": {
+ "stateCleared": "modified",
+ },
+ "rsbuild.module-federation.config.ts": {
+ "stateCleared": "modified",
+ },
"src/main/webapp/404.html": {
"stateCleared": "modified",
},
@@ -1907,24 +1898,6 @@ exports[`generator - vue microservice-oauth2-withAdminUi(true)-skipJhipsterDepen
"vitest.config.mts": {
"stateCleared": "modified",
},
- "webpack/config.js": {
- "stateCleared": "modified",
- },
- "webpack/vue.utils.js": {
- "stateCleared": "modified",
- },
- "webpack/webpack.common.js": {
- "stateCleared": "modified",
- },
- "webpack/webpack.dev.js": {
- "stateCleared": "modified",
- },
- "webpack/webpack.microfrontend.js": {
- "stateCleared": "modified",
- },
- "webpack/webpack.prod.js": {
- "stateCleared": "modified",
- },
}
`;
diff --git a/generators/vue/files-vue.ts b/generators/vue/files-vue.ts
index e70af0479916..655aedc206c8 100644
--- a/generators/vue/files-vue.ts
+++ b/generators/vue/files-vue.ts
@@ -37,17 +37,10 @@ export const vueFiles = {
}),
],
microfrontend: [
- clientRootTemplatesBlock({
+ {
condition: generator => generator.microfrontend,
- templates: [
- 'webpack/config.js',
- 'webpack/webpack.common.js',
- 'webpack/webpack.dev.js',
- 'webpack/webpack.prod.js',
- 'webpack/vue.utils.js',
- 'webpack/webpack.microfrontend.js.jhi.vue',
- ],
- }),
+ templates: ['rsbuild.module-federation.config.ts', 'rsbuild.config.ts.jhi.vue'],
+ },
{
condition: generator => generator.microfrontend,
...clientApplicationTemplatesBlock(),
@@ -56,14 +49,15 @@ export const vueFiles = {
{
condition: generator => generator.microfrontend,
...clientSrcTemplatesBlock(),
- templates: [
- 'microfrontends/entities-menu.component-test.ts',
- 'microfrontends/entities-menu-test.vue',
- 'microfrontends/entities-router-test.ts',
- ],
+ templates: ['microfrontends/entities-menu.component-test.ts', 'microfrontends/entities-router-test.ts'],
+ },
+ {
+ condition: generator => generator.enableTranslation && generator.microfrontend,
+ ...clientSrcTemplatesBlock(),
+ templates: ['microfrontends/entities-menu-test.vue'],
},
{
- condition: generator => generator.applicationTypeMicroservice,
+ condition: generator => generator.enableTranslation && generator.applicationTypeMicroservice,
...clientApplicationTemplatesBlock(),
templates: ['entities/entities-menu.spec.ts'],
},
diff --git a/generators/vue/generator.ts b/generators/vue/generator.ts
index e2d65daa2091..f33c409d5379 100644
--- a/generators/vue/generator.ts
+++ b/generators/vue/generator.ts
@@ -31,7 +31,6 @@ import {
getTypescriptKeyType as getTSKeyType,
generateTestEntityId as getTestEntityId,
} from '../client/support/index.js';
-import { createNeedleCallback } from '../base/support/index.js';
import { writeEslintClientRootConfigFile } from '../javascript/generators/eslint/support/tasks.js';
import { cleanupEntitiesFiles, postWriteEntityFiles, writeEntityFiles } from './entity-files-vue.js';
import cleanupOldFilesTask from './cleanup.js';
@@ -54,6 +53,24 @@ export default class VueGenerator extends BaseApplicationGenerator {
}
}
+ get composing() {
+ return this.asComposingTaskGroup({
+ async composing() {
+ if (
+ this.jhipsterConfig.microfrontend ||
+ this.jhipsterConfig.applicationType === 'microservice' ||
+ (this.jhipsterConfig.microfrontends ?? []).length > 0
+ ) {
+ await this.composeWithJHipster('jhipster:javascript:rsbuild');
+ }
+ },
+ });
+ }
+
+ get [BaseApplicationGenerator.COMPOSING]() {
+ return this.delegateTasksToBlueprint(() => this.composing);
+ }
+
get loading() {
return this.asLoadingTaskGroup({
loadPackageJson({ application }) {
@@ -85,21 +102,8 @@ export default class VueGenerator extends BaseApplicationGenerator {
webappEnumerationsDir: app => `${app.clientWebappDir}shared/model/enumerations/`,
});
},
- prepareForTemplates({ application, source }) {
+ prepareForTemplates({ application }) {
application.addPrettierExtensions?.(['html', 'vue', 'css', 'scss']);
-
- source.addWebpackConfig = args => {
- const webpackPath = `${application.clientRootDir}webpack/webpack.common.js`;
- const ignoreNonExisting = this.sharedData.getControl().ignoreNeedlesError && 'Webpack configuration file not found';
- this.editFile(
- webpackPath,
- { ignoreNonExisting },
- createNeedleCallback({
- needle: 'jhipster-needle-add-webpack-config',
- contentToAdd: `,${args.config}`,
- }),
- );
- };
},
});
}
@@ -175,7 +179,16 @@ export default class VueGenerator extends BaseApplicationGenerator {
get postWriting() {
return this.asPostWritingTaskGroup({
addIndexAsset({ source, application }) {
- if (application.microfrontend) return;
+ if (application.microfrontend) {
+ this.packageJson.merge({
+ devDependencies: {
+ '@rsbuild/plugin-sass': 'latest',
+ '@rsbuild/plugin-vue': 'latest',
+ },
+ });
+ return;
+ }
+
source.addExternalResourceToRoot!({
resource: '',
comment: 'Workaround https://github.com/axios/axios/issues/5622',
diff --git a/generators/vue/support/update-languages.ts b/generators/vue/support/update-languages.ts
index fdf3eb45c3d5..bbd67554db1e 100644
--- a/generators/vue/support/update-languages.ts
+++ b/generators/vue/support/update-languages.ts
@@ -88,7 +88,7 @@ export default function updateLanguagesTask(this: BaseGenerator, taskParam: Upda
updateLanguagesInPipeTask.call(this, taskParam);
updateLanguagesInConfigTask.call(this, taskParam);
if (taskParam.application.microfrontend) {
- updateLanguagesInWebpackTask.call(this, taskParam);
+ // updateLanguagesInWebpackTask.call(this, taskParam);
}
updateLanguagesInDayjsConfigurationTask.call(this, taskParam, {
configurationFile: `${taskParam.application.clientSrcDir}app/shared/config/dayjs.ts`,
diff --git a/generators/vue/templates/package.json.ejs b/generators/vue/templates/package.json.ejs
index bae1f6baa4f9..e0fad3934a47 100644
--- a/generators/vue/templates/package.json.ejs
+++ b/generators/vue/templates/package.json.ejs
@@ -59,29 +59,12 @@
"@module-federation/utilities": "<%= nodeDependencies['@module-federation/utilities'] %>",
<%_ } _%>
<%_ if (microfrontend) { _%>
- "@originjs/vite-plugin-federation": "1.3.3",
- "browser-sync-webpack-plugin": "<%= nodeDependencies['browser-sync-webpack-plugin'] %>",
- "copy-webpack-plugin": "<%= nodeDependencies['copy-webpack-plugin'] %>",
- "css-loader": "<%= nodeDependencies['css-loader'] %>",
- "css-minimizer-webpack-plugin": "<%= nodeDependencies['css-minimizer-webpack-plugin'] %>",
- "html-webpack-plugin": "<%= nodeDependencies['html-webpack-plugin'] %>",
<%_ if (enableTranslation) { _%>
"folder-hash": "<%= nodeDependencies['folder-hash'] %>",
"merge-jsons-webpack-plugin": "<%= nodeDependencies['merge-jsons-webpack-plugin'] %>",
<%_ } _%>
- "mini-css-extract-plugin": "<%= nodeDependencies['mini-css-extract-plugin'] %>",
- "postcss-loader": "<%= nodeDependencies['postcss-loader'] %>",
- "sass-loader": "<%= nodeDependencies['sass-loader'] %>",
- "terser-webpack-plugin": "<%= nodeDependencies['terser-webpack-plugin'] %>",
- "ts-loader": "<%= nodeDependencies['ts-loader'] %>",
"vue-loader": "<%= nodeDependencies['vue-loader'] %>",
"vue-style-loader": "<%= nodeDependencies['vue-style-loader'] %>",
- "webpack": "<%= nodeDependencies['webpack'] %>",
- "webpack-bundle-analyzer": "<%= nodeDependencies['webpack-bundle-analyzer'] %>",
- "webpack-cli": "<%= nodeDependencies['webpack-cli'] %>",
- "webpack-dev-server": "<%= nodeDependencies['webpack-dev-server'] %>",
- "webpack-merge": "<%= nodeDependencies['webpack-merge'] %>",
- "workbox-webpack-plugin": "<%= nodeDependencies['workbox-webpack-plugin'] %>",
<%_ } _%>
"@eslint/js": null,
"@pinia/testing": "<%= nodeDependencies['@pinia/testing'] %>",
@@ -125,13 +108,8 @@
"default_environment": "prod"
},
"scripts": {
-<%_ if (microfrontend) { %>
- "prettier:check": "prettier --check \"{,src/**/,webpack/,.blueprint/**/}*.{<%= prettierExtensions %>}\"",
- "prettier:format": "prettier --write \"{,src/**/,webpack/,.blueprint/**/}*.{<%= prettierExtensions %>}\"",
-<%_ } else { %>
"prettier:check": "prettier --check \"{,src/**/,.blueprint/**/}*.{<%= prettierExtensions %>}\"",
"prettier:format": "prettier --write \"{,src/**/,.blueprint/**/}*.{<%= prettierExtensions %>}\"",
-<%_ } %>
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"cleanup": "rimraf <%= this.relativeDir(clientRootDir, temporaryDir) %>",
@@ -148,25 +126,16 @@
"test:watch": "<%= clientPackageManager %> run vitest",
"watch": "concurrently npm:start<% if(!skipServer) { %> npm:backend:start<% } %>",
"webapp:build": "<%= clientPackageManager %> run clean-www && <%= clientPackageManager %> run webapp:build:dev --",
-<%_ if (microfrontend) { %>
- "webapp:build:dev": "<%= clientPackageManager %> run webpack -- --mode development --env stats=minimal",
- "webapp:build:prod": "<%= clientPackageManager %> run webpack -- --mode production --env stats=minimal",
- "webapp:dev": "<%= clientPackageManager %> run webpack-dev-server -- --mode development --env stats=normal",
-<%_ } else { %>
+<%_ if (!microfrontend) { %>
+ "vite-serve": "vite",
+ "vite-build": "vite build",
"webapp:build:dev": "<%= clientPackageManager %> run vite-build",
"webapp:build:prod": "<%= clientPackageManager %> run vite-build",
"webapp:dev": "<%= clientPackageManager %> run vite-serve",
"webapp:serve": "<%= clientPackageManager %> run vite-serve",
<%_ } %>
"webapp:prod": "<%= clientPackageManager %> run clean-www && <%= clientPackageManager %> run webapp:build:prod --",
- "webapp:test": "<%= clientPackageManager %> run test --",
-<%_ if (microfrontend) { %>
- "webpack-dev-server": "webpack serve --config webpack/webpack.common.js",
- "webpack": "webpack --config webpack/webpack.common.js"
-<%_ } else { %>
- "vite-serve": "vite",
- "vite-build": "vite build"
-<%_ } %>
+ "webapp:test": "<%= clientPackageManager %> run test --"
},
"browserslist": [
"> 1%",
diff --git a/generators/vue/templates/rsbuild.config.ts.jhi.vue.ejs b/generators/vue/templates/rsbuild.config.ts.jhi.vue.ejs
new file mode 100644
index 000000000000..30a725303692
--- /dev/null
+++ b/generators/vue/templates/rsbuild.config.ts.jhi.vue.ejs
@@ -0,0 +1,83 @@
+<%#
+ Copyright 2013-2024 the original author or authors from the JHipster project.
+
+ This file is part of the JHipster project, see https://www.jhipster.tech/
+ for more information.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-%>
+<&_ if (fragment.importsSection) { -&>
+import { pluginVue } from '@rsbuild/plugin-vue';
+import { pluginSass } from '@rsbuild/plugin-sass';
+<%_ if (microfrontend) { _%>
+import { mfConfig } from './rsbuild.module-federation.config.js';
+<%_ } _%>
+<&_ } -&>
+
+<&_ if (fragment.pluginsSection) { -&>
+ pluginVue(),
+ pluginSass(),
+<&_ } -&>
+
+<&_ if (fragment.configSection) { -&>
+ source: {
+ entry: {
+ index: './app/<%= microfrontend ? 'index' : 'main' %>.ts',
+ },
+ define: {
+ I18N_HASH: '"generated_hash"',
+ SERVER_API_URL: '"/"',
+ APP_VERSION: `"${process.env.APP_VERSION ? process.env.APP_VERSION : 'DEV'}"`,
+ },
+ alias: {
+ vue$: '@vue/compat/dist/vue.esm-bundler.js',
+ '@': path.resolve(__dirname, './<%= this.relativeDir(clientRootDir, clientSrcDir) %>app'),
+ },
+ },
+ server: {
+ port: <%= devServerPort %>,
+ proxy: [
+ {
+ context: [
+ '/api',
+ '/services',
+ '/management',
+ '/v3/api-docs',
+ '/h2-console',
+<%_ if (authenticationTypeOauth2) { _%>
+ '/oauth2',
+ '/login',
+<%_ } _%>
+ '/auth'
+ ],
+ target: 'http://localhost:<%= applicationTypeMicroservice ? gatewayServerPort : serverPort %>',
+ secure: false,
+ },
+<%_ if (communicationSpringWebsocket) { _%>
+ {
+ context: [
+ '/websocket'
+ ],
+ target: 'ws://localhost:<%= applicationTypeMicroservice ? gatewayServerPort : serverPort %>',
+ ws: true
+ }
+<%_ } _%>
+ ],
+ historyApiFallback: true,
+ },
+<%_ if (microfrontend) { _%>
+ moduleFederation: {
+ options: mfConfig,
+ },
+<%_ } _%>
+<&_ } -&>
diff --git a/generators/vue/templates/rsbuild.module-federation.config.ts.ejs b/generators/vue/templates/rsbuild.module-federation.config.ts.ejs
new file mode 100644
index 000000000000..33c6c53a6c6e
--- /dev/null
+++ b/generators/vue/templates/rsbuild.module-federation.config.ts.ejs
@@ -0,0 +1,52 @@
+<%#
+ Copyright 2013-2024 the original author or authors from the JHipster project.
+
+ This file is part of the JHipster project, see https://www.jhipster.tech/
+ for more information.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-%>
+import packageJson from './package.json' assert { type: 'json' };
+import type { Rspack } from '@rsbuild/core';
+
+// Microfrontend api, should match across gateway and microservices.
+const apiVersion = '0.0.1';
+
+const sharedDefaults = { singleton: true, strictVersion: true, requiredVersion: apiVersion };
+const shareMappings = (...mappings) => Object.fromEntries(mappings.map(map => [map, { ...sharedDefaults, version: apiVersion }]));
+
+const shareDependencies = ({ skipList = [] } = {}) =>
+ Object.fromEntries(
+ Object.entries(packageJson.dependencies)
+ .filter(([dependency]) => !skipList.includes(dependency))
+ .map(([dependency, version]) => [dependency, { ...sharedDefaults, version, requiredVersion: version }]),
+ );
+
+export const mfConfig = {
+ name: '<%= lowercaseBaseName %>',
+<%_ if (applicationTypeMicroservice) { _%>
+ exposes: {
+ './entities-router': './app/router/entities',
+ './entities-menu': './app/entities/entities-menu',
+ },
+<%_ } _%>
+ filename: 'remoteEntry.js',
+ shared: {
+ ...shareDependencies(),
+ ...shareMappings(
+ '@/shared/security/authority',
+ '@/shared/alert/alert.service',
+ '@/locale/translation.service',
+ ),
+ },
+} satisfies Rspack.ModuleFederationPluginOptions;
diff --git a/generators/vue/templates/src/main/webapp/app/main.ts.ejs b/generators/vue/templates/src/main/webapp/app/main.ts.ejs
index 86c4dffc215b..26abcebc1252 100644
--- a/generators/vue/templates/src/main/webapp/app/main.ts.ejs
+++ b/generators/vue/templates/src/main/webapp/app/main.ts.ejs
@@ -186,7 +186,7 @@ const app = createApp({
provide('trackerService', useTrackerService({ authenticated }));
<%_ } _%>
-<%_ if (applicationTypeMicroservice && microfrontend) { _%>
+<%_ if (enableTranslation && applicationTypeMicroservice && microfrontend) { _%>
provide('microfrontendI18n', false);
<%_ } _%>
},
diff --git a/generators/vue/templates/vite.config.mts.ejs b/generators/vue/templates/vite.config.mts.ejs
index 572fd11ac6a2..733884e36a47 100644
--- a/generators/vue/templates/vite.config.mts.ejs
+++ b/generators/vue/templates/vite.config.mts.ejs
@@ -21,20 +21,10 @@ import { existsSync } from 'node:fs';
import { normalizePath } from 'vite'
import {
-<%_ if (microfrontend) { _%>
- mergeConfig,
-<%_ } _%>
defineConfig,
} from 'vite';
import vue from '@vitejs/plugin-vue';
import { viteStaticCopy } from 'vite-plugin-static-copy';
-<%_ if (microfrontend) { _%>
-import federation from "@originjs/vite-plugin-federation";
-
- <%_ if (applicationTypeGateway) { _%>
-const sharedAppVersion = '0.0.0';
- <%_ } _%>
-<%_ } _%>
const getFileFromRepo = (file: string) =>
existsSync(fileURLToPath(new URL(`../node_modules/${file}`, import.meta.url)))
@@ -122,63 +112,6 @@ let config = defineConfig({
},
});
-<%_ if (microfrontend) { _%>
-config = mergeConfig(config, {
- build: {
- modulePreload: false,
- minify: false,
- target: ['chrome89', 'edge89', 'firefox89', 'safari15'],
- },
- plugins: [
- federation({
- name: '<%= lowercaseBaseName %>',
-<%_ if (applicationTypeGateway) { _%>
- remotes: {
- <%_ for (const remote of microfrontends) { _%>
- '@<%= remote.lowercaseBaseName %>': `/<%= remote.endpointPrefix %>/assets/remoteEntry.js`,
- <%_ } _%>
- },
-<%_ } _%>
-<%_ if (applicationTypeMicroservice) { _%>
- exposes: {
- './entities-router': './<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/router/entities',
- './entities-menu': './<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/entities/entities-menu.vue',
- },
-<%_ } _%>
- shared: {
- '@vuelidate/core': {},
- '@vuelidate/validators': {},
- axios: {},
- // 'bootstrap-vue': {},
- vue: {
- packagePath: '@vue/compat/dist/vue.esm-bundler.js',
- },
- 'vue-i18n': {},
- 'vue-router': {},
- pinia: {},
- '@/shared/security/authority': {
- packagePath: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/shared/security/authority',
-<%_ if (applicationTypeGateway) { _%>
- version: sharedAppVersion,
-<%_ } _%>
- },
- '@/shared/alert/alert.service': {
- packagePath: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/shared/alert/alert.service',
-<%_ if (applicationTypeGateway) { _%>
- version: sharedAppVersion,
-<%_ } _%>
- },
- '@/locale/translation.service': {
- packagePath: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/locale/translation.service',
-<%_ if (applicationTypeGateway) { _%>
- version: sharedAppVersion,
-<%_ } _%>
- },
- },
- }),
- ],
-});
-<%_ } _%>
// jhipster-needle-add-vite-config - JHipster will add custom config
export default config;
diff --git a/generators/vue/templates/webpack/config.js.ejs b/generators/vue/templates/webpack/config.js.ejs
deleted file mode 100644
index fe10699613d9..000000000000
--- a/generators/vue/templates/webpack/config.js.ejs
+++ /dev/null
@@ -1,48 +0,0 @@
-'use strict';
-
-<%_ if (buildToolUnknown) { _%>
-const packageJson = require('./../package.json');
-<%_ } _%>
-
-module.exports = {
- serverApiUrl: '',
-<%_ if (buildToolUnknown) { _%>
- version: packageJson.version,
-<%_ } else { _%>
- // APP_VERSION is passed as an environment variable from the Gradle / Maven build tasks.
- version: process.env.APP_VERSION || 'DEV',
-<%_ } _%>
-
- dev: {
- hotReload: <%= !microfrontend %>,
-
- // https://webpack.js.org/configuration/devtool/#development
- devtool: 'cheap-module-source-map',
-
- // If you have problems debugging vue-files in devtools,
- // set this to false - it *may* help
- // https://vue-loader.vuejs.org/en/options.html#cachebusting
- cacheBusting: true,
-
- cssSourceMap: true,
- },
-
- build: {
- productionSourceMap: true,
- // https://webpack.js.org/configuration/devtool/#production
- devtool: 'source-map',
-
- // Gzip off by default as many popular static hosts such as
- // Surge or Netlify already gzip all static assets for you.
- // Before setting to `true`, make sure to:
- // npm install --save-dev compression-webpack-plugin
- productionGzip: false,
- productionGzipExtensions: ['js', 'css'],
-
- // Run the build command with an extra argument to
- // View the bundle analyzer report after build finishes:
- // `npm run build --report`
- // Set to `true` or `false` to always turn it on or off
- bundleAnalyzerReport: process.env.npm_config_report,
- },
-};
diff --git a/generators/vue/templates/webpack/vue.utils.js.ejs b/generators/vue/templates/webpack/vue.utils.js.ejs
deleted file mode 100644
index 6552b8c4165e..000000000000
--- a/generators/vue/templates/webpack/vue.utils.js.ejs
+++ /dev/null
@@ -1,92 +0,0 @@
-'use strict';
-const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-const sass = require('sass');
-
-const config = require('./config');
-
-const sourceMapEnabled = production => (production ? config.build.productionSourceMap : config.dev.cssSourceMap);
-
-const cssLoaders = options => {
- options = options || {};
-
- const cssLoader = {
- loader: 'css-loader',
- options: {
- url: false,
- sourceMap: options.sourceMap,
- esModule: false,
- },
- };
-
- const postcssLoader = {
- loader: 'postcss-loader',
- options: {
- sourceMap: options.sourceMap,
- },
- };
-
- // generate loader string to be used with extract text plugin
- function generateLoaders(loader, loaderOptions) {
- const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader];
-
- if (loader) {
- loaders.push({
- loader: `${loader}-loader`,
- options: { ...loaderOptions, sourceMap: options.sourceMap },
- });
- }
-
- // Extract CSS when that option is specified
- // (which is the case during production build)
- return [options.extract ? MiniCssExtractPlugin.loader : 'vue-style-loader'].concat(loaders);
- }
-
- // https://vue-loader.vuejs.org/en/configurations/extract-css.html
- return {
- css: generateLoaders(),
- postcss: generateLoaders(),
- less: generateLoaders('less'),
- sass: generateLoaders('sass', { indentedSyntax: true, implementation: sass }),
- scss: generateLoaders('sass', { implementation: sass }),
- stylus: generateLoaders('stylus'),
- styl: generateLoaders('stylus'),
- };
-};
-
-// Generate loaders for standalone style files (outside of .vue)
-const styleLoaders = options => {
- const output = [];
- const loaders = cssLoaders(options);
-
- for (const extension in loaders) {
- const loader = loaders[extension];
- output.push({
- test: new RegExp(`\\.${extension}$`),
- use: loader,
- });
- }
-
- return output;
-};
-
-const vueLoaderConfig = production => ({
- loaders: cssLoaders({
- sourceMap: sourceMapEnabled(production),
- extract: production,
- }),
- cssSourceMap: sourceMapEnabled(production),
- cacheBusting: config.dev.cacheBusting,
- transformToRequire: {
- video: ['src', 'poster'],
- source: 'src',
- img: 'src',
- image: 'xlink:href',
- },
- hotReload: config.dev.hotReload,
-});
-
-module.exports = {
- cssLoaders,
- styleLoaders,
- vueLoaderConfig,
-};
diff --git a/generators/vue/templates/webpack/webpack.common.js.ejs b/generators/vue/templates/webpack/webpack.common.js.ejs
deleted file mode 100644
index fcaa45cf8d4b..000000000000
--- a/generators/vue/templates/webpack/webpack.common.js.ejs
+++ /dev/null
@@ -1,185 +0,0 @@
-'use strict';
-const path = require('path');
-const { merge } = require('webpack-merge');
-const { VueLoaderPlugin } = require('vue-loader');
-const CopyWebpackPlugin = require('copy-webpack-plugin');
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-<%_ if (enableTranslation) { _%>
-const { hashElement } = require('folder-hash');
-const MergeJsonWebpackPlugin = require('merge-jsons-webpack-plugin');
-<%_ } _%>
-
-const { DefinePlugin } = require('webpack');
-const { vueLoaderConfig } = require('./vue.utils');
-const config = require('./config');
-
-function resolve(dir = '') {
- return path.join(__dirname, '..', dir);
-}
-
-module.exports = async (env, options) => {
- const development = options.mode === 'development';
-<%_ if (enableTranslation) { _%>
- const languagesHash = await hashElement(resolve('<%= this.relativeDir(clientRootDir, clientSrcDir) %>i18n'), {
- algo: 'md5',
- encoding: 'hex',
- files: { include: ['*.json'] },
- });
-
-<%_ } _%>
- return merge(
- {
- mode: options.mode,
- context: resolve(),
-<%_ if (applicationTypeGateway && microfrontend) { _%>
- experiments: {
- topLevelAwait: true,
- },
-<%_ } _%>
- entry: {
- app: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/<%= microfrontend ? 'index' : 'main' %>.ts',
- },
- output: {
- path: resolve('<%= this.relativeDir(clientRootDir, clientDistDir) %>'),
- },
- resolve: {
- extensions: ['.ts', '.js', '.vue', '.json'],
- alias: {
- vue$: '@vue/compat/dist/vue.esm-bundler.js',
- '@': resolve('<%= this.relativeDir(clientRootDir, clientSrcDir) %>app'),
- },
- },
- devServer: {
-<%_ if (microfrontend) { _%>
- hot: config.dev.hotReload,
-<%_ } _%>
- static: {
- directory: './<%= this.relativeDir(clientRootDir, clientDistDir) %>',
- },
- port: <%= devServerPort %>,
- proxy: [
- {
- context: [
- '/api',
- '/services',
- '/management',
- '/v3/api-docs',
- '/h2-console',
-<%_ if (authenticationTypeOauth2) { _%>
- '/oauth2',
- '/login',
-<%_ } _%>
- '/auth'
- ],
- target: 'http://localhost:<%= applicationTypeMicroservice ? gatewayServerPort : serverPort %>',
- secure: false,
- },
-<%_ if (communicationSpringWebsocket) { _%>
- {
- context: [
- '/websocket'
- ],
- target: 'ws://localhost:<%= applicationTypeMicroservice ? gatewayServerPort : serverPort %>',
- ws: true
- }
-<%_ } _%>
- ],
- historyApiFallback: true,
- },
- cache: {
- // 1. Set cache type to filesystem
- type: 'filesystem',
- cacheDirectory: resolve('<%= this.relativeDir(clientRootDir, temporaryDir) %>webpack'),
- buildDependencies: {
- // 2. Add your config as buildDependency to get cache invalidation on config change
- config: [
- __filename,
- path.resolve(__dirname, 'config.js'),
- path.resolve(__dirname, 'vue.utils.js'),
- path.resolve(__dirname, `webpack.${development ? 'dev' : 'prod'}.js`),
- path.resolve(__dirname, '../.postcssrc.js'),
- path.resolve(__dirname, '../tsconfig.json'),
- ],
- },
- },
- module: {
- rules: [
- {
- test: /\.vue$/,
- loader: 'vue-loader',
- options: {
- ...vueLoaderConfig(!development),
- },
- },
- {
- test: /\.ts$/,
- use: [
- {
- loader: 'ts-loader',
- options: {
- appendTsSuffixTo: ['\\.vue$'],
- happyPackMode: true,
- transpileOnly: true,
- configFile: 'tsconfig.app.json',
- },
- },
- ],
- include: [resolve('src'), resolve('test')],
- },
- {
- test: /\.(png|jpe?g|gif|svg|mp4|webm|ogg|mp3|wav|flac|aac|woff2?|eot|ttf|otf)/,
- type: 'asset/resource',
- },
- ],
- },
- plugins: [
- new DefinePlugin({
-<%_ if (enableTranslation) { _%>
- I18N_HASH: JSON.stringify(languagesHash.hash),
-<%_ } _%>
- APP_VERSION: JSON.stringify(config.version),
- SERVER_API_URL: JSON.stringify(config.serverApiUrl),
- __VUE_PROD_DEVTOOLS__: false,
- }),
- new HtmlWebpackPlugin({
- base: '/',
- template: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>index.html',
- }),
- new VueLoaderPlugin(),
- new CopyWebpackPlugin({
- patterns: [
- {
- // https://github.com/swagger-api/swagger-ui/blob/v4.6.1/swagger-ui-dist-package/README.md
- context: require('swagger-ui-dist').getAbsoluteFSPath(),
- from: '*.{js,css,html,png}',
- to: 'swagger-ui/',
- globOptions: { ignore: ['**/index.html'] },
- },
- {
- from: path.join(path.dirname(require.resolve('axios/package.json')), 'dist/axios.min.js'),
- to: 'swagger-ui/',
- },
- { from: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>swagger-ui/', to: 'swagger-ui/' },
- { from: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>content/', to: 'content/' },
- { from: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>favicon.ico', to: 'favicon.ico' },
- {
- from: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>manifest.webapp',
- to: 'manifest.webapp',
- },
- // jhipster-needle-add-assets-to-webpack - JHipster will add/remove third-party resources in this array
- { from: './<%= this.relativeDir(clientRootDir, clientSrcDir) %>robots.txt', to: 'robots.txt' },
- ],
- })<% if (enableTranslation) { %>,
- new MergeJsonWebpackPlugin({
- output: {
- groupBy: [
- // jhipster-needle-i18n-language-webpack - JHipster will add/remove languages in this array
- ],
- },
- }),<% } %>
- ],
- },
- await require(`./webpack.${development ? 'dev' : 'prod'}`)(env, options)
- // jhipster-needle-add-webpack-config - JHipster will add custom config
- );
-};
diff --git a/generators/vue/templates/webpack/webpack.dev.js.ejs b/generators/vue/templates/webpack/webpack.dev.js.ejs
deleted file mode 100644
index 56341dd4d9a9..000000000000
--- a/generators/vue/templates/webpack/webpack.dev.js.ejs
+++ /dev/null
@@ -1,70 +0,0 @@
-<%#
- Copyright 2013-2024 the original author or authors from the JHipster project.
-
- This file is part of the JHipster project, see https://www.jhipster.tech/
- for more information.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- https://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--%>
-'use strict';
-const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
-
-const { styleLoaders } = require('./vue.utils');
-const config = require('./config');
-
-module.exports = (env, options) => {
- const devConfig = {
- module: {
- rules: styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }),
- },
- // cheap-module-eval-source-map is faster for development
- devtool: config.dev.devtool,
- output: {
- filename: 'app/[name].[contenthash].bundle.js',
- chunkFilename: 'app/[id].[chunkhash].chunk.js',
- },
- optimization: {
- moduleIds: 'named',
- },
- plugins: [],
- };
- if (!options.env.WEBPACK_SERVE) return devConfig;
- devConfig.plugins.push(
- new BrowserSyncPlugin(
- {
- host: 'localhost',
- port: 9000,
- proxy: {
- target: `http://localhost:${options.watch ? '<%= applicationTypeMicroservice ? gatewayServerPort : serverPort %>' : '<%= devServerPort %>'}`,
- ws: true,
- },
- socket: {
- clients: {
- heartbeatTimeout: 60000,
- },
- },
- /*
- ,ghostMode: { // uncomment this part to disable BrowserSync ghostMode; https://github.com/jhipster/generator-jhipster/issues/11116
- clicks: false,
- location: false,
- forms: false,
- scroll: false
- } */
- },
- {
- reload: true,
- },
- ),
- );
- return devConfig;
-};
diff --git a/generators/vue/templates/webpack/webpack.microfrontend.js.jhi.vue.ejs b/generators/vue/templates/webpack/webpack.microfrontend.js.jhi.vue.ejs
deleted file mode 100644
index e30946d381c2..000000000000
--- a/generators/vue/templates/webpack/webpack.microfrontend.js.jhi.vue.ejs
+++ /dev/null
@@ -1,45 +0,0 @@
-<%#
- Copyright 2013-2024 the original author or authors from the JHipster project.
-
- This file is part of the JHipster project, see https://www.jhipster.tech/
- for more information.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- https://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--%>
-<&_ if (fragment.configSection) { -&>
-<%_ if (applicationTypeGateway && clientFrameworkVue) { _%>
- resolve: {
- fallback: {
- // Workaround https://github.com/module-federation/universe/issues/1575
- path: false,
- },
- },
-<%_ } _%>
-<&_ } -&>
-
-<&_ if (fragment.moduleFederationSection) { -&>
-<%_ if (applicationTypeMicroservice) { _%>
- exposes: {
- './entities-router': './<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/router/entities',
- './entities-menu': './<%= this.relativeDir(clientRootDir, clientSrcDir) %>app/entities/entities-menu',
- },
-<%_ } _%>
- shared: {
- ...shareDependencies(),
- ...shareMappings(
- '@/shared/security/authority',
- '@/shared/alert/alert.service',
- '@/locale/translation.service',
- ),
- },
-<&_ } -&>
diff --git a/generators/vue/templates/webpack/webpack.prod.js.ejs b/generators/vue/templates/webpack/webpack.prod.js.ejs
deleted file mode 100644
index 18dba308038f..000000000000
--- a/generators/vue/templates/webpack/webpack.prod.js.ejs
+++ /dev/null
@@ -1,126 +0,0 @@
-<%#
- Copyright 2013-2024 the original author or authors from the JHipster project.
-
- This file is part of the JHipster project, see https://www.jhipster.tech/
- for more information.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- https://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--%>
-'use strict';
-const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
-const WorkboxPlugin = require('workbox-webpack-plugin');
-const TerserPlugin = require('terser-webpack-plugin');
-
-const { styleLoaders } = require('./vue.utils');
-const config = require('./config');
-
-const webpackConfig = {
- module: {
- rules: styleLoaders({
- sourceMap: config.build.productionSourceMap,
- extract: true,
- usePostCSS: true,
- }),
- },
- devtool: config.build.productionSourceMap ? config.build.devtool : false,
- output: {
- filename: 'app/[name].[contenthash].bundle.js',
- chunkFilename: 'app/[id].[chunkhash].chunk.js',
- },
- optimization: {
- moduleIds: 'deterministic',
- minimizer: [
- '...',
- new CssMinimizerPlugin({
- parallel: true,
- }),
- ],
- splitChunks: {
- cacheGroups: {
- commons: {
- test: /[\\/]node_modules[\\/]/,
- name: 'vendors',
- chunks: 'all',
- },
- },
- },
- },
- plugins: [
- new TerserPlugin({
- terserOptions: {
- compress: {
- arrows: false,
- collapse_vars: false,
- comparisons: false,
- computed_props: false,
- hoist_funs: false,
- hoist_props: false,
- hoist_vars: false,
- inline: false,
- loops: false,
- negate_iife: false,
- properties: false,
- reduce_funcs: false,
- reduce_vars: false,
- switches: false,
- toplevel: false,
- typeofs: false,
- booleans: true,
- if_return: true,
- sequences: true,
- unused: true,
- conditionals: true,
- dead_code: true,
- evaluate: true,
- },
- mangle: {
- safari10: true,
- },
- },
- parallel: true,
- extractComments: false,
- }),
- // extract css into its own file
- new MiniCssExtractPlugin({
- filename: 'content/[name].[contenthash].css',
- chunkFilename: 'content/[id].css',
- }),
- new WorkboxPlugin.GenerateSW({
- clientsClaim: true,
- skipWaiting: true,
- exclude: [/swagger-ui/],
- }),
- ],
-};
-
-if (config.build.productionGzip) {
- const CompressionWebpackPlugin = require('compression-webpack-plugin');
-
- webpackConfig.plugins.push(
- new CompressionWebpackPlugin({
- asset: '[path].gz[query]',
- algorithm: 'gzip',
- test: new RegExp(`\\.(${config.build.productionGzipExtensions.join('|')})$`),
- threshold: 10240,
- minRatio: 0.8,
- }),
- );
-}
-
-if (config.build.bundleAnalyzerReport) {
- const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
- webpackConfig.plugins.push(new BundleAnalyzerPlugin());
-}
-
-module.exports = async () => webpackConfig;
diff --git a/lib/jhipster/default-application-options.ts b/lib/jhipster/default-application-options.ts
index 02350746f4db..567e7c122525 100644
--- a/lib/jhipster/default-application-options.ts
+++ b/lib/jhipster/default-application-options.ts
@@ -76,7 +76,9 @@ const {
GRADLE_ENTERPRISE_HOST,
} = OptionNames;
-const commonDefaultOptions: Partial = {
+type ApplicationDefaults = Partial;
+
+const commonDefaultOptions: ApplicationDefaults = {
[AUTHENTICATION_TYPE]: JWT,
[BUILD_TOOL]: MAVEN,
[DTO_SUFFIX]: OptionValues[DTO_SUFFIX],
@@ -89,8 +91,8 @@ const commonDefaultOptions: Partial = {
[WEBSOCKET]: (OptionValues[WEBSOCKET] as Record).no,
};
-export function getConfigWithDefaults(customOptions: string | Record = {}) {
- const applicationType = typeof customOptions === 'string' ? customOptions : customOptions.applicationType;
+export function getConfigWithDefaults(customOptions: ApplicationDefaults = {}) {
+ const applicationType = customOptions.applicationType;
if (applicationType === GATEWAY) {
return getConfigForGatewayApplication(customOptions);
}
@@ -100,7 +102,7 @@ export function getConfigWithDefaults(customOptions: string | Record prop + '-bar', prop2: 'won\'t override' },
* );
*/
- applicationDefaults: (...defaults: Record[]) => void;
+ applicationDefaults: (...defaults: (Partial & Record)[]) => void;
};
type TaskParamWithApplication> = TaskParamWithControl & {
diff --git a/test-integration/jdl-samples/ms-mf-vue-consul-oauth2-mysql-memcached/blog-store.jdl b/test-integration/jdl-samples/ms-mf-vue-consul-oauth2-mysql-memcached/blog-store.jdl
index 88761d6c8e14..c0758e54fec5 100644
--- a/test-integration/jdl-samples/ms-mf-vue-consul-oauth2-mysql-memcached/blog-store.jdl
+++ b/test-integration/jdl-samples/ms-mf-vue-consul-oauth2-mysql-memcached/blog-store.jdl
@@ -31,6 +31,7 @@ application {
serviceDiscoveryType consul
testFrameworks [cypress]
microfrontends [blog, notification]
+ enableTranslation false
}
entities UserData, Product
}
@@ -51,6 +52,7 @@ application {
serverPort 8081
serviceDiscoveryType consul
testFrameworks [cypress]
+ enableTranslation false
}
entities Blog, Post, Tag
}
@@ -72,6 +74,7 @@ application {
serverPort 8082
serviceDiscoveryType consul
testFrameworks [cypress]
+ enableTranslation false
}
entities Product
}
@@ -94,6 +97,7 @@ application {
serverPort 8083
serviceDiscoveryType consul
testFrameworks [cypress]
+ enableTranslation false
}
entities Notification
}