DCP stands out as a versatile solution that caters to diverse developer preferences and requirements. On the frontend, DCP holds the capability to seamlessly integrate with a wide array of commonly used frontend frameworks, empowering developers to leverage their preferred tools and technologies to build dynamic and engaging user interfaces. Meanwhile, in the backend, DCP provides developers with the freedom to select their preferred backend language for creating microservices and APIs. With DCP, developers have the flexibility to utilize the language best suited to their expertise and project requirements, ensuring seamless integration and efficient functionality across their backend infrastructure.
Here are some of the steps to create new VueJS application, to be used inside DCP ecosystem.
For this step you can copy existing project or use Vue CLI to create a new one.
Inside your .env
file add
STANDALONE_SINGLE_SPA=true
VUE_APP_IS_APP_NAME=SAW
VUE_APP_IS_APP_VALIDATED=false
VUE_APP_API_ENV=dev
VUE_APP_API_URL=false
VUE_APP_I18N_LOCALE=en
VUE_APP_I18N_FALLBACK_LOCALE=en
Create environment files for all necessary environments by copying .env
file, and changing VUE_APP_API_ENV
.
.env.dev
- VUE_APP_API_ENV=dev
.env.stage
- VUE_APP_API_ENV=stage
.env.test
- VUE_APP_API_ENV=test
.env.standalone
- VUE_APP_API_ENV=dev
.env.prod
- VUE_APP_API_ENV=prod
Later in the process, will use that VUE_APP_API_ENV
to populate correct VUE_APP_API_URL
.
Add new line inside vue.config.js
to give your application port that is not used by other Vue or Angular application. For Vue applications ports starting with 80
like 8081
are used by convention. Check other applications and add a port number that is not used yet.
module.exports = defineConfig({
devServer: { port: 8082, https: true},
})
If your application use Vue CLI you have one step, that should do all:
vue add single-spa
If your application does not use Vue CLI you need to do run these commands:
npm i --save single-spa-vue
npm i --save systemjs-webpack-interop
Create a file at the same level as your main.js/ts
called set-public-path.js
import { setPublicPath } from 'systemjs-webpack-interop';
setPublicPath('applicationName');
In main.ts
file add this lines
import { h, createApp } from 'vue';
import './set-public-path.js';
import singleSpaVue from 'single-spa-vue';
// Only for examples
import router from './router';
import i18n from './i18n';
const vueLifecycles = singleSpaVue({
createApp,
appOptions: {
i18n,
render() {
return h(App, {
// single-spa props are available on the "this" object. Forward them to your component as needed.
// https://single-spa.js.org/docs/building-applications#lifecycle-props
// if you uncomment these, remember to add matching prop definitions for them in your App.vue file.
/*
name: this.name,
mountParcel: this.mountParcel,
singleSpa: this.singleSpa,
*/
});
},
},
handleInstance(app) {
app.use(i18n);
app.use(router);
// And all other library, that you will use
},
});
export const bootstrap = vueLifecycles.bootstrap;
export const mount = vueLifecycles.mount;
export const unmount = vueLifecycles.unmount;
More information here
Inside Vue applications some of DCP Libraries. to be imported as a Git Submodules
Run git submodule add ../../Modules/dc-shared.git src/libs/dc-shared
.
From here we can use DcpSync Service
Base class and model. Also, we have some other models and enums like MessagesTypeEnum
.
Run git submodule add ../../Modules/dc-assets.git src/assets
.
Inside we have vue.styles.scss
reusable styles.
Run git submodule add ../../Modules/dc-user.git src/libs/dc-user
From where we use models like UserDateFormatSettings
, UserSettingsModel
and UserTimeFormatSettings
.
Run git submodule add ../../Modules/dc-core.git src/libs/dc-core
Inside vue.config.js add this line process.env.VUE_APP_API_URL = require('./src/libs/dc-core/src/core/api.json').saw[process.env.VUE_APP_API_ENV];
TODO: This one needs to be extracted from SAW application, after we make some refactoring in existing shared
folder.
The idea is to have ready to use Vue components, services, composable, enums etc.
that can be shared between VueJS applications like DcShared
is shared between Angular applications.
Because Dc Libraries contains a lot ot Angular specific code, this will break the VueJS build.
To not be affected by this code, during build, we need to make additional setup inside tsconfig.json.
{
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx",
"src/libs/**/vue/*"
],
"exclude": [
"node_modules",
"src/libs/**/*"
]
}
The new line in exclude
section "src/libs/**/*"
will exclude from build all code from Dc Libraries.
The new line in include
section "src/libs/**/vue/*"
will include all code, that we specifically set inside some Dc Libraries /vue
folders if there is.
One of the main ideas in DCP is the UI to look similar in all applications.
To achieve that we use in all Angular applications
Material Icons,
Kendo UI for Angular,
Angular Material and
Bootstrap 4.6.0
.
Fallowing the same path, for Vue applications we use
Material Icons and Material Design Icons,
Kendo UI for Vue,
Vuetify (as an alternative to Angular Material) and
Bootstrap 4.6.0
.
Note
: Version of Bootstrap is important, because styles are global and can affect existing applications.
Run npm i --save material-icons
@import "~material-icons/iconfont/material-icons.css";
is already inside DcShared vue.styles.scss
Run npm i --save @mdi/font
This one will be set as a default icon set to Vuetify later.
Run npm i --save [email protected]
@import "~bootstrap/scss/bootstrap";
is already inside DcShared vue.styles.scss
TODO
More information here.
Inside App.vue
add
<style lang="scss" scoped>
@import "~@progress/kendo-theme-material/dist/all.css";
</style>
Next thing that we need to do is to be sure that the Kendo UI
styles that we import will not affect other applications.
The problem is that Kendo use same component classes for both VueJS and Angular, but because of different HTML structure, classes with same names, have different implementations.
To achieve that we will add additional step to all build processes later. Now we will add npm packages
that we need and create gulpfile.js
file
npm install --save-dev gulp
npm install --save-dev gulp-replace
gulpfile.js
file to your root directoryconst gulp = require('gulp');
const replace = require('gulp-replace');
gulp.task('replaceKendoCss', function () {
return gulp.src(['./dist/js/app.js', './dist/js/app.js.map'])
.pipe(replace(' k--', ' revert--'))
.pipe(replace('k-icon', 'revert-icon'))
.pipe(replace('.k-', '.dcp-vue-k-'))
.pipe(replace(' k-', ' dcp-vue-k-'))
.pipe(replace('\'k-', '\'dcp-vue-k-'))
.pipe(replace('"k-', '"dcp-vue-k-'))
.pipe(replace(' revert--', ' k--'))
.pipe(replace('revert-icon', 'k-icon'))
.pipe(gulp.dest('./dist/js/'));
});
This way we will change all Kendo UI for Vue class names from .k-
to .dcp-vue-k-
,
and class names will be different from the one in Kendo UI for Angular.
To not affect some code like .k-icon
or for (let k; k < 12; k--)
we make revert process for it.
During build, we need to be sure, that we get the latest code from current environment branches of all Dc Libraries.
Inside package.json
add build processes for different environments.
{
"scripts": {
"build:dev": "npm run getLatestSubmodules:dev && vue-cli-service build --mode dev && npm run replaceKendoCss",
"build:prod": "npm run getLatestSubmodules:main && vue-cli-service build --mode prod && npm run replaceKendoCss",
"build:stage": "npm run getLatestSubmodules:stage && vue-cli-service build --mode stage && npm run replaceKendoCss",
"build:test": "npm run getLatestSubmodules:test && vue-cli-service build --mode test && npm run replaceKendoCss",
"getLatestSubmodules:dev": "git submodule foreach git pull origin develop --allow-unrelated-histories",
"getLatestSubmodules:test": "git submodule foreach git pull origin test --allow-unrelated-histories",
"getLatestSubmodules:stage": "git submodule foreach git pull origin stage --allow-unrelated-histories",
"getLatestSubmodules:main": "git submodule foreach git pull origin main --allow-unrelated-histories",
"replaceKendoCss": "gulp replaceKendoCss"
}
}
For easy change between branches during development we will add npm run checkout:BRANCH
commands, that will help us to not change all libraries one by one.
Also, we will add command npm run start:spa
that will be used to build the application for Import map overrides.
{
"scripts": {
"checkout:dev": "git checkout develop && git submodule foreach git checkout develop",
"checkout:main": "git checkout main && git submodule foreach git checkout main",
"checkout:stage": "git checkout stage && git submodule foreach git checkout stage",
"checkout:test": "git checkout test && git submodule foreach git checkout test",
"start": "vue-cli-service serve --mode standalone",
"start:spa": "vue-cli-service serve"
}
}
To register new application in Base App three steps are required
<script type="systemjs-importmap">
{
"imports": {
<!--...-->
"@dcp/[applicationName]": "https://dcp-[gxpOrNonGxp].domain.com/[applicationBuildFolder]/[applicationMainFile]?version=1"
<!--...-->
}
}
</script>
camelCase
that will be easy to understand when is in use with import map override for local development.
nongxp
. Once the app is validated deploy path will be changed to gxp
.app-mvda
/ or /app-login
/. This is setup inside .gitlab-ci.yml
file for the application.main.js
, and for VueJS applications app.js
.<!--index.html-->
<script>
/*...*/
const routes = constructRoutes(
document.querySelector("#single-spa-layout"),
{
loaders: {
/*...*/
"[applicationLoader]": createLoaderHtml('[ApplicationName]'),
}
}
);
/*...*/
</script>
Product and Process Monitoring
, Administration
), that will be shown to users during loading.Here we have three cases
<!--index.html-->
<head>
<template id="single-spa-layout">
<single-spa-router>
<route path="/app/:siteId">
<route path="/[applicationPath]">
<!-- We load here applications that contains top navigation and side menu inside -->
<application name="@dcp/[applicationName]" loader="[applicationLoader]"></application>
</route>
<route path="/menu">
<div class="wrapper">
<nav class="side-menu">
<application name="@dcp/side-menu"></application>
</nav>
<header class="top-navigation">
<application name="@dcp/top-navigation"></application>
</header>
<main class="main-content dcp-app-wrapper">
<route path="/[applicationPath]">
<!-- We load here applications that will use Top Navigation, and Side Menu Applications -->
<application name="@dcp/[applicationName]" loader="[applicationLoader]"></application>
</route>
</main>
</div>
</route>
</route>
<route path="/[applicationShareablePath]">
<!-- We load here application content that need to be visible for users that are not logged in -->
<application name="@dcp/[applicationName]" loader="[applicationLoader]"></application>
</route>
</single-spa-router>
</template>
</head>
mvda
, Administration use administration
. This is setup inside application router.