From c3ef1d2981fc48f11e3f7a0cc1813a0178cc2b8b Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Mon, 7 Oct 2024 14:18:58 -0300 Subject: [PATCH 1/6] vue: @module-federation/utilities dependency is gateway only --- generators/vue/generator.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/generators/vue/generator.ts b/generators/vue/generator.ts index c86fa58f65a0..bb99f50b8928 100644 --- a/generators/vue/generator.ts +++ b/generators/vue/generator.ts @@ -205,17 +205,24 @@ export default class VueGenerator extends BaseApplicationGenerator { } }, addMicrofrontendDependencies({ application }) { - if (!application.microfrontend) return; - if (application.clientBundlerVite) { + const { applicationTypeGateway, clientBundlerVite, clientBundlerWebpack, enableTranslation, microfrontend } = application; + if (!microfrontend) return; + if (clientBundlerVite) { this.packageJson.merge({ devDependencies: { '@originjs/vite-plugin-federation': '1.3.6', }, }); - } else if (application.clientBundlerWebpack) { + } else if (clientBundlerWebpack) { + if (applicationTypeGateway) { + this.packageJson.merge({ + devDependencies: { + '@module-federation/utilities': null, + }, + }); + } this.packageJson.merge({ devDependencies: { - '@module-federation/utilities': null, 'browser-sync-webpack-plugin': null, 'copy-webpack-plugin': null, 'css-loader': null, @@ -234,7 +241,7 @@ export default class VueGenerator extends BaseApplicationGenerator { 'webpack-dev-server': null, 'webpack-merge': null, 'workbox-webpack-plugin': null, - ...(application.enableTranslation + ...(enableTranslation ? { 'folder-hash': null, 'merge-jsons-webpack-plugin': null, From 162eae581050c3b4e17cf7bba74fa5a261b9655a Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Mon, 7 Oct 2024 07:12:49 -0300 Subject: [PATCH 2/6] drop vue webpack support --- generators/client/files-common.ts | 3 +- generators/client/generator.ts | 4 +- generators/vue/files-vue.ts | 10 - generators/vue/generator.ts | 83 ++------ generators/vue/resources/package.json | 22 +-- generators/vue/support/update-languages.ts | 17 -- .../vue/templates/webpack/config.js.ejs | 48 ----- .../vue/templates/webpack/vue.utils.js.ejs | 92 --------- .../templates/webpack/webpack.common.js.ejs | 185 ------------------ .../vue/templates/webpack/webpack.dev.js.ejs | 70 ------- .../vue/templates/webpack/webpack.prod.js.ejs | 126 ------------ lib/jhipster/default-application-options.ts | 2 +- 12 files changed, 18 insertions(+), 644 deletions(-) delete mode 100644 generators/vue/templates/webpack/config.js.ejs delete mode 100644 generators/vue/templates/webpack/vue.utils.js.ejs delete mode 100644 generators/vue/templates/webpack/webpack.common.js.ejs delete mode 100644 generators/vue/templates/webpack/webpack.dev.js.ejs delete mode 100644 generators/vue/templates/webpack/webpack.prod.js.ejs diff --git a/generators/client/files-common.ts b/generators/client/files-common.ts index f27e23e2d8db..bb864653d969 100644 --- a/generators/client/files-common.ts +++ b/generators/client/files-common.ts @@ -25,8 +25,7 @@ export const files = { templates: ['README.md.jhi.client', '.prettierignore.jhi.client'], }, clientRootTemplatesBlock({ - condition: generator => - generator.microfrontend && generator.clientBundlerWebpack && (generator.clientFrameworkVue || generator.clientFrameworkReact), + condition: generator => generator.microfrontend && generator.clientBundlerWebpack && generator.clientFrameworkReact, templates: ['webpack/webpack.microfrontend.js.jhi'], }), { diff --git a/generators/client/generator.ts b/generators/client/generator.ts index 690ef2b802e1..203916162ab6 100644 --- a/generators/client/generator.ts +++ b/generators/client/generator.ts @@ -251,10 +251,8 @@ 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 { - throw new Error(`Client framework ${application.clientFramework} doesn't support microfrontends`); } }, }); diff --git a/generators/vue/files-vue.ts b/generators/vue/files-vue.ts index dcf63b6c2ce7..1c56fbd21c3b 100644 --- a/generators/vue/files-vue.ts +++ b/generators/vue/files-vue.ts @@ -41,16 +41,6 @@ export const vueFiles = { condition: generator => generator.microfrontend, templates: ['module-federation.config.cjs'], }), - clientRootTemplatesBlock({ - condition: ctx => ctx.microfrontend && ctx.clientBundlerWebpack, - templates: [ - 'webpack/config.js', - 'webpack/webpack.common.js', - 'webpack/webpack.dev.js', - 'webpack/webpack.prod.js', - 'webpack/vue.utils.js', - ], - }), { condition: generator => generator.microfrontend, ...clientApplicationTemplatesBlock(), diff --git a/generators/vue/generator.ts b/generators/vue/generator.ts index bb99f50b8928..44a4ae84d0bd 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'; @@ -85,24 +84,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 => { - if (!application.clientBundlerWebpack) { - throw new Error('This application is not webpack based'); - } - 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}`, - }), - ); - }; }, }); } @@ -148,9 +131,19 @@ export default class VueGenerator extends BaseApplicationGenerator { get writing() { return this.asWritingTaskGroup({ - async cleanup({ control }) { + async cleanup({ control, application }) { await control.cleanupFiles({ '8.6.1': ['.eslintrc.json', '.eslintignore'], + '8.7.2': [ + [ + application.microfrontend!, + 'webpack/config.js', + 'webpack/webpack.common.js', + 'webpack/webpack.dev.js', + 'webpack/webpack.prod.js', + 'webpack/vue.utils.js', + ], + ], }); }, cleanupOldFilesTask, @@ -178,7 +171,7 @@ export default class VueGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ addPackageJsonScripts({ application }) { - const { clientBundlerVite, clientBundlerWebpack, clientPackageManager, prettierExtensions } = application; + const { clientBundlerVite, clientPackageManager, prettierExtensions } = application; if (clientBundlerVite) { this.packageJson.merge({ scripts: { @@ -190,18 +183,6 @@ export default class VueGenerator extends BaseApplicationGenerator { 'vite-build': 'vite build', }, }); - } else if (clientBundlerWebpack) { - this.packageJson.merge({ - scripts: { - 'prettier:check': `prettier --check "{,src/**/,webpack/,.blueprint/**/}*.{${prettierExtensions}}"`, - 'prettier:format': `prettier --write "{,src/**/,webpack/,.blueprint/**/}*.{${prettierExtensions}}"`, - '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`, - 'webpack-dev-server': 'webpack serve --config webpack/webpack.common.js', - webpack: 'webpack --config webpack/webpack.common.js', - }, - }); } }, addMicrofrontendDependencies({ application }) { @@ -213,42 +194,6 @@ export default class VueGenerator extends BaseApplicationGenerator { '@originjs/vite-plugin-federation': '1.3.6', }, }); - } else if (clientBundlerWebpack) { - if (applicationTypeGateway) { - this.packageJson.merge({ - devDependencies: { - '@module-federation/utilities': null, - }, - }); - } - this.packageJson.merge({ - devDependencies: { - 'browser-sync-webpack-plugin': null, - 'copy-webpack-plugin': null, - 'css-loader': null, - 'css-minimizer-webpack-plugin': null, - 'html-webpack-plugin': null, - 'mini-css-extract-plugin': null, - 'postcss-loader': null, - 'sass-loader': null, - 'terser-webpack-plugin': null, - 'ts-loader': null, - 'vue-loader': null, - 'vue-style-loader': null, - webpack: null, - 'webpack-bundle-analyzer': null, - 'webpack-cli': null, - 'webpack-dev-server': null, - 'webpack-merge': null, - 'workbox-webpack-plugin': null, - ...(enableTranslation - ? { - 'folder-hash': null, - 'merge-jsons-webpack-plugin': null, - } - : {}), - }, - }); } }, addIndexAsset({ source, application }) { @@ -284,7 +229,7 @@ export default class VueGenerator extends BaseApplicationGenerator { end({ application }) { this.log.ok('Vue application generated successfully.'); this.log.log( - chalk.green(` Start your Webpack development server with: + chalk.green(` Start your development server with: ${chalk.yellow.bold(`${application.nodePackageManager} start`)} `), ); diff --git a/generators/vue/resources/package.json b/generators/vue/resources/package.json index cdfc9cfe0f5e..f48464aca872 100644 --- a/generators/vue/resources/package.json +++ b/generators/vue/resources/package.json @@ -32,43 +32,23 @@ "@vue/tsconfig": "0.5.1", "autoprefixer": "10.4.20", "axios-mock-adapter": "2.0.0", - "browser-sync-webpack-plugin": "2.3.0", - "copy-webpack-plugin": "12.0.2", - "css-loader": "7.1.2", - "css-minimizer-webpack-plugin": "7.0.0", "eslint": "9.12.0", "eslint-plugin-prettier": "5.2.1", "eslint-plugin-vue": "9.28.0", "flush-promises": "1.0.2", - "folder-hash": "4.0.4", "happy-dom": "14.12.3", - "html-webpack-plugin": "5.6.0", - "merge-jsons-webpack-plugin": "2.0.1", - "mini-css-extract-plugin": "2.9.1", "numeral": "2.0.6", "postcss-import": "16.1.0", - "postcss-loader": "8.1.1", "postcss-url": "10.1.3", "rimraf": "5.0.8", "sass": "1.79.4", - "sass-loader": "16.0.2", "sinon": "19.0.2", - "terser-webpack-plugin": "5.3.10", - "ts-loader": "9.5.1", "typescript": "5.6.2", "typescript-eslint": "8.8.0", "vite": "5.4.8", "vite-plugin-static-copy": "1.0.6", "vitest": "2.1.2", "vitest-sonar-reporter": "2.0.0", - "vue-loader": "17.4.2", - "vue-style-loader": "4.1.3", - "vue-tsc": "2.1.6", - "webpack": "5.95.0", - "webpack-bundle-analyzer": "4.10.2", - "webpack-cli": "5.1.4", - "webpack-dev-server": "5.1.0", - "webpack-merge": "6.0.1", - "workbox-webpack-plugin": "7.1.0" + "vue-tsc": "2.1.6" } } diff --git a/generators/vue/support/update-languages.ts b/generators/vue/support/update-languages.ts index 5f515134dd78..e6631219ba46 100644 --- a/generators/vue/support/update-languages.ts +++ b/generators/vue/support/update-languages.ts @@ -70,26 +70,9 @@ function updateLanguagesInConfigTask(this: BaseGenerator, { application, control ); } -function updateLanguagesInWebpackTask(this: BaseGenerator, { application, control = {} }: UpdateClientLanguagesTaskParam) { - const { clientSrcDir, languages } = application; - const { ignoreNeedlesError: ignoreNonExisting } = control; - let newContent = 'groupBy: [\n'; - languages?.forEach(language => { - newContent += ` { pattern: './${clientSrcDir}i18n/${language}/*.json', fileName: './i18n/${language}.json' },\n`; - }); - newContent += ' // jhipster-needle-i18n-language-webpack - JHipster will add/remove languages in this array\n ]'; - - this.editFile('webpack/webpack.common.js', { ignoreNonExisting }, content => - content.replace(/groupBy:.*\[([^\]]*jhipster-needle-i18n-language-webpack[^\]]*)\]/g, newContent), - ); -} - export default function updateLanguagesTask(this: BaseGenerator, taskParam: UpdateClientLanguagesTaskParam) { updateLanguagesInPipeTask.call(this, taskParam); updateLanguagesInConfigTask.call(this, taskParam); - if (taskParam.application.clientBundlerWebpack) { - updateLanguagesInWebpackTask.call(this, taskParam); - } updateLanguagesInDayjsConfigurationTask.call(this, taskParam, { configurationFile: `${taskParam.application.clientSrcDir}app/shared/config/dayjs.ts`, commonjs: true, 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.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 4853618c54cd..767a49e69cf5 100644 --- a/lib/jhipster/default-application-options.ts +++ b/lib/jhipster/default-application-options.ts @@ -120,7 +120,7 @@ export function getConfigForClientApplication(options: ApplicationDefaults = {}) options[CLIENT_THEME_VARIANT] = 'primary'; } if (clientFramework === 'vue') { - options.clientBundler = options.microfrontend || options.applicationType === 'microservice' ? 'webpack' : 'vite'; + options.clientBundler = 'vite'; } else if (clientFramework === 'react') { options.clientBundler = 'webpack'; } else if (clientFramework === 'angular') { From 1e823b54b0ac2b9fe44b0c81c32d09960e4aa4a2 Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Mon, 7 Oct 2024 14:24:54 -0300 Subject: [PATCH 3/6] Revert "drop vue webpack support" This reverts commit 162eae581050c3b4e17cf7bba74fa5a261b9655a. --- generators/client/files-common.ts | 3 +- generators/client/generator.ts | 4 +- generators/vue/files-vue.ts | 10 + generators/vue/generator.ts | 83 ++++++-- generators/vue/resources/package.json | 22 ++- generators/vue/support/update-languages.ts | 17 ++ .../vue/templates/webpack/config.js.ejs | 48 +++++ .../vue/templates/webpack/vue.utils.js.ejs | 92 +++++++++ .../templates/webpack/webpack.common.js.ejs | 185 ++++++++++++++++++ .../vue/templates/webpack/webpack.dev.js.ejs | 70 +++++++ .../vue/templates/webpack/webpack.prod.js.ejs | 126 ++++++++++++ lib/jhipster/default-application-options.ts | 2 +- 12 files changed, 644 insertions(+), 18 deletions(-) create mode 100644 generators/vue/templates/webpack/config.js.ejs create mode 100644 generators/vue/templates/webpack/vue.utils.js.ejs create mode 100644 generators/vue/templates/webpack/webpack.common.js.ejs create mode 100644 generators/vue/templates/webpack/webpack.dev.js.ejs create mode 100644 generators/vue/templates/webpack/webpack.prod.js.ejs diff --git a/generators/client/files-common.ts b/generators/client/files-common.ts index bb864653d969..f27e23e2d8db 100644 --- a/generators/client/files-common.ts +++ b/generators/client/files-common.ts @@ -25,7 +25,8 @@ export const files = { templates: ['README.md.jhi.client', '.prettierignore.jhi.client'], }, clientRootTemplatesBlock({ - condition: generator => generator.microfrontend && generator.clientBundlerWebpack && generator.clientFrameworkReact, + condition: generator => + generator.microfrontend && generator.clientBundlerWebpack && (generator.clientFrameworkVue || generator.clientFrameworkReact), templates: ['webpack/webpack.microfrontend.js.jhi'], }), { diff --git a/generators/client/generator.ts b/generators/client/generator.ts index 203916162ab6..690ef2b802e1 100644 --- a/generators/client/generator.ts +++ b/generators/client/generator.ts @@ -251,8 +251,10 @@ export default class JHipsterClientGenerator extends BaseApplicationGenerator { source.addWebpackConfig({ config: `${conditional}require('./webpack.microfrontend')(config, options, targetOptions)`, }); - } else if (application.clientFrameworkReact) { + } else if (application.clientFrameworkVue || application.clientFrameworkReact) { source.addWebpackConfig({ config: "require('./webpack.microfrontend')({ serve: options.env.WEBPACK_SERVE })" }); + } else { + throw new Error(`Client framework ${application.clientFramework} doesn't support microfrontends`); } }, }); diff --git a/generators/vue/files-vue.ts b/generators/vue/files-vue.ts index 1c56fbd21c3b..dcf63b6c2ce7 100644 --- a/generators/vue/files-vue.ts +++ b/generators/vue/files-vue.ts @@ -41,6 +41,16 @@ export const vueFiles = { condition: generator => generator.microfrontend, templates: ['module-federation.config.cjs'], }), + clientRootTemplatesBlock({ + condition: ctx => ctx.microfrontend && ctx.clientBundlerWebpack, + templates: [ + 'webpack/config.js', + 'webpack/webpack.common.js', + 'webpack/webpack.dev.js', + 'webpack/webpack.prod.js', + 'webpack/vue.utils.js', + ], + }), { condition: generator => generator.microfrontend, ...clientApplicationTemplatesBlock(), diff --git a/generators/vue/generator.ts b/generators/vue/generator.ts index 44a4ae84d0bd..bb99f50b8928 100644 --- a/generators/vue/generator.ts +++ b/generators/vue/generator.ts @@ -31,6 +31,7 @@ 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'; @@ -84,8 +85,24 @@ export default class VueGenerator extends BaseApplicationGenerator { webappEnumerationsDir: app => `${app.clientWebappDir}shared/model/enumerations/`, }); }, - prepareForTemplates({ application }) { + prepareForTemplates({ application, source }) { application.addPrettierExtensions?.(['html', 'vue', 'css', 'scss']); + + source.addWebpackConfig = args => { + if (!application.clientBundlerWebpack) { + throw new Error('This application is not webpack based'); + } + 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}`, + }), + ); + }; }, }); } @@ -131,19 +148,9 @@ export default class VueGenerator extends BaseApplicationGenerator { get writing() { return this.asWritingTaskGroup({ - async cleanup({ control, application }) { + async cleanup({ control }) { await control.cleanupFiles({ '8.6.1': ['.eslintrc.json', '.eslintignore'], - '8.7.2': [ - [ - application.microfrontend!, - 'webpack/config.js', - 'webpack/webpack.common.js', - 'webpack/webpack.dev.js', - 'webpack/webpack.prod.js', - 'webpack/vue.utils.js', - ], - ], }); }, cleanupOldFilesTask, @@ -171,7 +178,7 @@ export default class VueGenerator extends BaseApplicationGenerator { get postWriting() { return this.asPostWritingTaskGroup({ addPackageJsonScripts({ application }) { - const { clientBundlerVite, clientPackageManager, prettierExtensions } = application; + const { clientBundlerVite, clientBundlerWebpack, clientPackageManager, prettierExtensions } = application; if (clientBundlerVite) { this.packageJson.merge({ scripts: { @@ -183,6 +190,18 @@ export default class VueGenerator extends BaseApplicationGenerator { 'vite-build': 'vite build', }, }); + } else if (clientBundlerWebpack) { + this.packageJson.merge({ + scripts: { + 'prettier:check': `prettier --check "{,src/**/,webpack/,.blueprint/**/}*.{${prettierExtensions}}"`, + 'prettier:format': `prettier --write "{,src/**/,webpack/,.blueprint/**/}*.{${prettierExtensions}}"`, + '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`, + 'webpack-dev-server': 'webpack serve --config webpack/webpack.common.js', + webpack: 'webpack --config webpack/webpack.common.js', + }, + }); } }, addMicrofrontendDependencies({ application }) { @@ -194,6 +213,42 @@ export default class VueGenerator extends BaseApplicationGenerator { '@originjs/vite-plugin-federation': '1.3.6', }, }); + } else if (clientBundlerWebpack) { + if (applicationTypeGateway) { + this.packageJson.merge({ + devDependencies: { + '@module-federation/utilities': null, + }, + }); + } + this.packageJson.merge({ + devDependencies: { + 'browser-sync-webpack-plugin': null, + 'copy-webpack-plugin': null, + 'css-loader': null, + 'css-minimizer-webpack-plugin': null, + 'html-webpack-plugin': null, + 'mini-css-extract-plugin': null, + 'postcss-loader': null, + 'sass-loader': null, + 'terser-webpack-plugin': null, + 'ts-loader': null, + 'vue-loader': null, + 'vue-style-loader': null, + webpack: null, + 'webpack-bundle-analyzer': null, + 'webpack-cli': null, + 'webpack-dev-server': null, + 'webpack-merge': null, + 'workbox-webpack-plugin': null, + ...(enableTranslation + ? { + 'folder-hash': null, + 'merge-jsons-webpack-plugin': null, + } + : {}), + }, + }); } }, addIndexAsset({ source, application }) { @@ -229,7 +284,7 @@ export default class VueGenerator extends BaseApplicationGenerator { end({ application }) { this.log.ok('Vue application generated successfully.'); this.log.log( - chalk.green(` Start your development server with: + chalk.green(` Start your Webpack development server with: ${chalk.yellow.bold(`${application.nodePackageManager} start`)} `), ); diff --git a/generators/vue/resources/package.json b/generators/vue/resources/package.json index f48464aca872..cdfc9cfe0f5e 100644 --- a/generators/vue/resources/package.json +++ b/generators/vue/resources/package.json @@ -32,23 +32,43 @@ "@vue/tsconfig": "0.5.1", "autoprefixer": "10.4.20", "axios-mock-adapter": "2.0.0", + "browser-sync-webpack-plugin": "2.3.0", + "copy-webpack-plugin": "12.0.2", + "css-loader": "7.1.2", + "css-minimizer-webpack-plugin": "7.0.0", "eslint": "9.12.0", "eslint-plugin-prettier": "5.2.1", "eslint-plugin-vue": "9.28.0", "flush-promises": "1.0.2", + "folder-hash": "4.0.4", "happy-dom": "14.12.3", + "html-webpack-plugin": "5.6.0", + "merge-jsons-webpack-plugin": "2.0.1", + "mini-css-extract-plugin": "2.9.1", "numeral": "2.0.6", "postcss-import": "16.1.0", + "postcss-loader": "8.1.1", "postcss-url": "10.1.3", "rimraf": "5.0.8", "sass": "1.79.4", + "sass-loader": "16.0.2", "sinon": "19.0.2", + "terser-webpack-plugin": "5.3.10", + "ts-loader": "9.5.1", "typescript": "5.6.2", "typescript-eslint": "8.8.0", "vite": "5.4.8", "vite-plugin-static-copy": "1.0.6", "vitest": "2.1.2", "vitest-sonar-reporter": "2.0.0", - "vue-tsc": "2.1.6" + "vue-loader": "17.4.2", + "vue-style-loader": "4.1.3", + "vue-tsc": "2.1.6", + "webpack": "5.95.0", + "webpack-bundle-analyzer": "4.10.2", + "webpack-cli": "5.1.4", + "webpack-dev-server": "5.1.0", + "webpack-merge": "6.0.1", + "workbox-webpack-plugin": "7.1.0" } } diff --git a/generators/vue/support/update-languages.ts b/generators/vue/support/update-languages.ts index e6631219ba46..5f515134dd78 100644 --- a/generators/vue/support/update-languages.ts +++ b/generators/vue/support/update-languages.ts @@ -70,9 +70,26 @@ function updateLanguagesInConfigTask(this: BaseGenerator, { application, control ); } +function updateLanguagesInWebpackTask(this: BaseGenerator, { application, control = {} }: UpdateClientLanguagesTaskParam) { + const { clientSrcDir, languages } = application; + const { ignoreNeedlesError: ignoreNonExisting } = control; + let newContent = 'groupBy: [\n'; + languages?.forEach(language => { + newContent += ` { pattern: './${clientSrcDir}i18n/${language}/*.json', fileName: './i18n/${language}.json' },\n`; + }); + newContent += ' // jhipster-needle-i18n-language-webpack - JHipster will add/remove languages in this array\n ]'; + + this.editFile('webpack/webpack.common.js', { ignoreNonExisting }, content => + content.replace(/groupBy:.*\[([^\]]*jhipster-needle-i18n-language-webpack[^\]]*)\]/g, newContent), + ); +} + export default function updateLanguagesTask(this: BaseGenerator, taskParam: UpdateClientLanguagesTaskParam) { updateLanguagesInPipeTask.call(this, taskParam); updateLanguagesInConfigTask.call(this, taskParam); + if (taskParam.application.clientBundlerWebpack) { + updateLanguagesInWebpackTask.call(this, taskParam); + } updateLanguagesInDayjsConfigurationTask.call(this, taskParam, { configurationFile: `${taskParam.application.clientSrcDir}app/shared/config/dayjs.ts`, commonjs: true, diff --git a/generators/vue/templates/webpack/config.js.ejs b/generators/vue/templates/webpack/config.js.ejs new file mode 100644 index 000000000000..fe10699613d9 --- /dev/null +++ b/generators/vue/templates/webpack/config.js.ejs @@ -0,0 +1,48 @@ +'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 new file mode 100644 index 000000000000..6552b8c4165e --- /dev/null +++ b/generators/vue/templates/webpack/vue.utils.js.ejs @@ -0,0 +1,92 @@ +'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 new file mode 100644 index 000000000000..fcaa45cf8d4b --- /dev/null +++ b/generators/vue/templates/webpack/webpack.common.js.ejs @@ -0,0 +1,185 @@ +'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 new file mode 100644 index 000000000000..56341dd4d9a9 --- /dev/null +++ b/generators/vue/templates/webpack/webpack.dev.js.ejs @@ -0,0 +1,70 @@ +<%# + 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.prod.js.ejs b/generators/vue/templates/webpack/webpack.prod.js.ejs new file mode 100644 index 000000000000..18dba308038f --- /dev/null +++ b/generators/vue/templates/webpack/webpack.prod.js.ejs @@ -0,0 +1,126 @@ +<%# + 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 767a49e69cf5..4853618c54cd 100644 --- a/lib/jhipster/default-application-options.ts +++ b/lib/jhipster/default-application-options.ts @@ -120,7 +120,7 @@ export function getConfigForClientApplication(options: ApplicationDefaults = {}) options[CLIENT_THEME_VARIANT] = 'primary'; } if (clientFramework === 'vue') { - options.clientBundler = 'vite'; + options.clientBundler = options.microfrontend || options.applicationType === 'microservice' ? 'webpack' : 'vite'; } else if (clientFramework === 'react') { options.clientBundler = 'webpack'; } else if (clientFramework === 'angular') { From a41f4b39fd0e78d1bbc3188d4a60275d2d501ef1 Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Mon, 7 Oct 2024 07:34:01 -0300 Subject: [PATCH 4/6] cleanup --- generators/vue/files-vue.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/generators/vue/files-vue.ts b/generators/vue/files-vue.ts index dcf63b6c2ce7..164df355d659 100644 --- a/generators/vue/files-vue.ts +++ b/generators/vue/files-vue.ts @@ -59,14 +59,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.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'], }, From 8fac971e07275522ada03e7be28ef87f0a8fca51 Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Mon, 7 Oct 2024 13:29:55 -0300 Subject: [PATCH 5/6] Revert "cleanup" This reverts commit f1cd2edef1e2d29cf78e256877331a5dcaf37b41. --- generators/vue/files-vue.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/generators/vue/files-vue.ts b/generators/vue/files-vue.ts index 164df355d659..dcf63b6c2ce7 100644 --- a/generators/vue/files-vue.ts +++ b/generators/vue/files-vue.ts @@ -59,15 +59,14 @@ export const vueFiles = { { condition: generator => generator.microfrontend, ...clientSrcTemplatesBlock(), - templates: ['microfrontends/entities-menu.component-test.ts', 'microfrontends/entities-router-test.ts'], - }, - { - condition: generator => generator.microfrontend, - ...clientSrcTemplatesBlock(), - templates: ['microfrontends/entities-menu-test.vue'], + templates: [ + 'microfrontends/entities-menu.component-test.ts', + 'microfrontends/entities-menu-test.vue', + 'microfrontends/entities-router-test.ts', + ], }, { - condition: generator => generator.enableTranslation && generator.applicationTypeMicroservice, + condition: generator => generator.applicationTypeMicroservice, ...clientApplicationTemplatesBlock(), templates: ['entities/entities-menu.spec.ts'], }, From b48e73b0cd5838b3c456e75bb7137b4f57d09777 Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Mon, 7 Oct 2024 14:31:09 -0300 Subject: [PATCH 6/6] vue: switch to @module-federation/vite --- .../templates/.prettierignore.jhi.ejs | 3 + generators/vue/generator.ts | 5 +- generators/vue/resources/package.json | 2 + .../templates/eslint.config.js.jhi.vue.ejs | 8 +- .../jhi-navbar/jhi-navbar.component.ts.ejs | 9 +++ .../src/main/webapp/app/router/index.ts.ejs | 20 +++++ generators/vue/templates/vite.config.mts.ejs | 79 +++---------------- lib/jhipster/default-application-options.ts | 2 +- 8 files changed, 57 insertions(+), 71 deletions(-) diff --git a/generators/javascript/generators/prettier/templates/.prettierignore.jhi.ejs b/generators/javascript/generators/prettier/templates/.prettierignore.jhi.ejs index 03b20a35aa15..8e07e3d4f48a 100644 --- a/generators/javascript/generators/prettier/templates/.prettierignore.jhi.ejs +++ b/generators/javascript/generators/prettier/templates/.prettierignore.jhi.ejs @@ -19,5 +19,8 @@ node_modules package-lock.json .git +<%_ if (clientFrameworkVue && microfrontend) { _%> +'.__mf__temp', +<%_ } _%> <&- fragments.render({ join: '\n\n' }) &> diff --git a/generators/vue/generator.ts b/generators/vue/generator.ts index bb99f50b8928..47686cf263a2 100644 --- a/generators/vue/generator.ts +++ b/generators/vue/generator.ts @@ -209,8 +209,11 @@ export default class VueGenerator extends BaseApplicationGenerator { if (!microfrontend) return; if (clientBundlerVite) { this.packageJson.merge({ + dependencies: applicationTypeGateway ? { + '@module-federation/runtime': null, + } : {}, devDependencies: { - '@originjs/vite-plugin-federation': '1.3.6', + '@module-federation/vite': null, }, }); } else if (clientBundlerWebpack) { diff --git a/generators/vue/resources/package.json b/generators/vue/resources/package.json index cdfc9cfe0f5e..4186f2ab6280 100644 --- a/generators/vue/resources/package.json +++ b/generators/vue/resources/package.json @@ -3,6 +3,7 @@ "@fortawesome/fontawesome-svg-core": "6.6.0", "@fortawesome/free-solid-svg-icons": "6.6.0", "@fortawesome/vue-fontawesome": "3.0.8", + "@module-federation/runtime": "0.6.9", "@stomp/rx-stomp": "2.0.0", "@vuelidate/core": "2.0.3", "@vuelidate/validators": "2.0.4", @@ -23,6 +24,7 @@ "devDependencies": { "@eslint/js": "9.12.0", "@module-federation/utilities": "3.1.15", + "@module-federation/vite": "1.1.1", "@pinia/testing": "0.1.6", "@tsconfig/node18": "18.2.4", "@types/node": "20.11.25", diff --git a/generators/vue/templates/eslint.config.js.jhi.vue.ejs b/generators/vue/templates/eslint.config.js.jhi.vue.ejs index 7a5a36fa442b..5a2b441fd314 100644 --- a/generators/vue/templates/eslint.config.js.jhi.vue.ejs +++ b/generators/vue/templates/eslint.config.js.jhi.vue.ejs @@ -22,7 +22,13 @@ import vue from 'eslint-plugin-vue'; <&_ } -&> <&_ if (fragment.configSection) { -&> - { ignores: ['<%- this.relativeDir(clientRootDir, clientDistDir) %>', '<%- temporaryDir %>'] }, + { ignores: [ +<%_ if (microfrontend) { _%> + '.__mf__temp', +<%_ } _%> + '<%- this.relativeDir(clientRootDir, clientDistDir) %>', + '<%- temporaryDir %>', + ] }, js.configs.recommended, ...tseslint.configs.recommended.map(config => config.name === 'typescript-eslint/base' ? config : { ...config, files: [ '**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts' ] }, diff --git a/generators/vue/templates/src/main/webapp/app/core/jhi-navbar/jhi-navbar.component.ts.ejs b/generators/vue/templates/src/main/webapp/app/core/jhi-navbar/jhi-navbar.component.ts.ejs index 320eb2781652..8489f80842a4 100644 --- a/generators/vue/templates/src/main/webapp/app/core/jhi-navbar/jhi-navbar.component.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/core/jhi-navbar/jhi-navbar.component.ts.ejs @@ -12,7 +12,11 @@ import EntitiesMenu from '@/entities/entities-menu.vue'; import { useStore } from '@/store'; import { useRouter } from 'vue-router'; <%_ if (applicationTypeGateway && microfrontend) { _%> + <%_ if (clientBundlerVite) { _%> +import { loadRemote } from '@module-federation/runtime'; + <%_ } else { _%> import { importRemote } from '@module-federation/utilities'; + <%_ } _%> <%_ } _%> export default defineComponent({ @@ -23,11 +27,16 @@ export default defineComponent({ <%_ if (applicationTypeGateway && microfrontend) { _%> <%_ for (const remote of microfrontends) { _%> '<%= remote.lowercaseBaseName %>-menu': defineAsyncComponent(() => { + <%_ if (clientBundlerVite) { _%> + return loadRemote(`<%= remote.lowercaseBaseName %>/entities-menu`) + .catch(() => import('@/core/error/error-loading.vue')); + <%_ } else { _%> return importRemote({ url: `./<%= remote.endpointPrefix %>`, scope: '<%= remote.lowercaseBaseName %>', module: './entities-menu', }).catch(() => import('@/core/error/error-loading.vue')); + <%_ } _%> }), <%_ } _%> <%_ } _%> diff --git a/generators/vue/templates/src/main/webapp/app/router/index.ts.ejs b/generators/vue/templates/src/main/webapp/app/router/index.ts.ejs index 38579df39062..9641092a2184 100644 --- a/generators/vue/templates/src/main/webapp/app/router/index.ts.ejs +++ b/generators/vue/templates/src/main/webapp/app/router/index.ts.ejs @@ -1,6 +1,10 @@ import { createRouter as createVueRouter, createWebHistory<% if (applicationTypeGateway && microfrontend) { %>, type RouteRecordRaw<% } %> } from 'vue-router'; <%_ if (applicationTypeGateway && microfrontend) { _%> + <%_ if (clientBundlerVite) { _%> +import { loadRemote, registerRemotes } from '@module-federation/runtime'; + <%_ } else { _%> import { importRemote } from '@module-federation/utilities'; + <%_ } _%> <%_ } _%> const Home = () => import('@/core/home/home.vue'); @@ -44,13 +48,29 @@ export const createRouter = () => createVueRouter({ const router = createRouter(); <%_ if (applicationTypeGateway && microfrontend) { _%> + <%_ if (clientBundlerVite) { _%> +registerRemotes([ + <%_ for (const remote of microfrontends) { _%> + { + name: '<%= remote.lowercaseBaseName %>', + entry: './<%= remote.endpointPrefix %>/remoteEntry.js', + type: 'module', + }, + <%_ } _%> +]); + <%_ } _%> + export const lazyRoutes = Promise.all([ <%_ for (const remote of microfrontends) { _%> + <%_ if (clientBundlerVite) { _%> + loadRemote(`<%= remote.lowercaseBaseName %>/entities-router`) + <%_ } else { _%> importRemote({ url: `./<%= remote.endpointPrefix %>`, scope: '<%= remote.lowercaseBaseName %>', module: './entities-router', }) + <%_ } _%> .then(<%= remote.lowercaseBaseName %>Router => { router.addRoute(<%= remote.lowercaseBaseName %>Router.default as RouteRecordRaw); return <%= remote.lowercaseBaseName %>Router.default; diff --git a/generators/vue/templates/vite.config.mts.ejs b/generators/vue/templates/vite.config.mts.ejs index 5b53609660c0..bedacddeabc3 100644 --- a/generators/vue/templates/vite.config.mts.ejs +++ b/generators/vue/templates/vite.config.mts.ejs @@ -19,20 +19,12 @@ import { fileURLToPath, URL } from 'node:url'; import { normalizePath } from 'vite' -import { -<%_ if (microfrontend && clientBundlerVite) { _%> - mergeConfig, -<%_ } _%> - defineConfig, -} from 'vite'; +import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { viteStaticCopy } from 'vite-plugin-static-copy'; <%_ if (microfrontend && clientBundlerVite) { _%> -import federation from "@originjs/vite-plugin-federation"; - - <%_ if (applicationTypeGateway) { _%> -const sharedAppVersion = '0.0.0'; - <%_ } _%> +import { federation } from '@module-federation/vite'; +import federationConfig from './module-federation.config.cjs'; <%_ } _%> const { getAbsoluteFSPath } = await import('swagger-ui-dist'); @@ -55,6 +47,9 @@ let config = defineConfig({ }, ], }), +<%_ if (microfrontend && clientBundlerVite) { _%> + federation(federationConfig), +<%_ } _%> ], root: fileURLToPath(new URL('./<%- this.relativeDir(clientRootDir, clientSrcDir) %>', import.meta.url)), publicDir: fileURLToPath(new URL('./<%- this.relativeDir(clientRootDir, clientDistDir) %>public', import.meta.url)), @@ -62,6 +57,11 @@ let config = defineConfig({ build: { emptyOutDir: true, outDir: fileURLToPath(new URL('./<%- this.relativeDir(clientRootDir, clientDistDir) %>', import.meta.url)), +<%_ if (microfrontend && clientBundlerVite) { _%> + modulePreload: false, + // Allow topLevelAwait by default, Use 'vite-plugin-top-level-await' plugin for lower target + target: ['chrome89', 'edge89', 'firefox89', 'safari15'], +<%_ } _%> rollupOptions: { input: { app: fileURLToPath(new URL('./<%- this.relativeDir(clientRootDir, clientSrcDir) %>index.html', import.meta.url)), @@ -116,63 +116,6 @@ let config = defineConfig({ }, }); -<%_ if (microfrontend && clientBundlerVite) { _%> -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/lib/jhipster/default-application-options.ts b/lib/jhipster/default-application-options.ts index 4853618c54cd..767a49e69cf5 100644 --- a/lib/jhipster/default-application-options.ts +++ b/lib/jhipster/default-application-options.ts @@ -120,7 +120,7 @@ export function getConfigForClientApplication(options: ApplicationDefaults = {}) options[CLIENT_THEME_VARIANT] = 'primary'; } if (clientFramework === 'vue') { - options.clientBundler = options.microfrontend || options.applicationType === 'microservice' ? 'webpack' : 'vite'; + options.clientBundler = 'vite'; } else if (clientFramework === 'react') { options.clientBundler = 'webpack'; } else if (clientFramework === 'angular') {