diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index d52016943..4fc191ba4 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -59,13 +59,13 @@ class Config extends FHCAPI_Controller $result['details'] = [ 'title' => $this->p->t('stv', 'tab_details'), - 'component' => './Stv/Studentenverwaltung/Details/Details.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Details.js', 'config' => $config['details'] ]; $result['notes'] = [ 'title' => $this->p->t('stv', 'tab_notes'), - 'component' => './Stv/Studentenverwaltung/Details/Notizen.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Notizen.js', 'config' => $config['notes'], 'showSuffix' => ($config['notes']['showCountNotes'] ?? false), 'suffixhelper' => APP_ROOT . 'public/js/helpers/Stv/Studentenverwaltung/Details/Notizen/NotizenSuffixHelper.js' @@ -73,7 +73,7 @@ class Config extends FHCAPI_Controller $result['contact'] = [ 'title' => $this->p->t('stv', 'tab_contact'), - 'component' => './Stv/Studentenverwaltung/Details/Kontakt.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Kontakt.js', 'config' => [ 'showBankaccount' => $this->permissionlib->isBerechtigt('mitarbeiter/bankdaten') || $this->permissionlib->isBerechtigt('student/bankdaten') @@ -81,20 +81,20 @@ class Config extends FHCAPI_Controller ]; $result['prestudent'] = [ 'title' => $this->p->t('stv', 'tab_prestudent'), - 'component' => './Stv/Studentenverwaltung/Details/Prestudent.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Prestudent.js', 'config' => $config['prestudent'] ]; $result['status'] = [ 'title' => 'Status', - 'component' => './Stv/Studentenverwaltung/Details/MultiStatus.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/MultiStatus.js' ]; $result['documents'] = [ 'title' => $this->p->t('stv', 'tab_documents'), - 'component' => './Stv/Studentenverwaltung/Details/Dokumente.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Dokumente.js' ]; $result['banking'] = [ 'title' => $this->p->t('stv', 'tab_banking'), - 'component' => './Stv/Studentenverwaltung/Details/Konto.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Konto.js', 'config' => [ 'showZahlungsbestaetigung' => (defined('ZAHLUNGSBESTAETIGUNG_ANZEIGEN') && ZAHLUNGSBESTAETIGUNG_ANZEIGEN), 'showBuchungsnr' => $this->permissionlib->isBerechtigt('admin'), @@ -106,20 +106,20 @@ class Config extends FHCAPI_Controller ]; $result['resources'] = [ 'title' => $this->p->t('stv', 'tab_resources'), - 'component' => './Stv/Studentenverwaltung/Details/Betriebsmittel.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Betriebsmittel.js' ]; $result['groups'] = [ 'title' => $this->p->t('stv', 'tab_groups'), - 'component' => './Stv/Studentenverwaltung/Details/Gruppen.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js' ]; $result['messages'] = [ 'title' => $this->p->t('stv', 'tab_messages'), - 'component' => './Stv/Studentenverwaltung/Details/Messages.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Messages.js' ]; $result['grades'] = [ 'title' => $this->p->t('stv', 'tab_grades'), - 'component' => './Stv/Studentenverwaltung/Details/Noten.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Noten.js', 'showOnlyWithUid' => true, 'config' => [ 'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE, @@ -132,29 +132,29 @@ class Config extends FHCAPI_Controller $result['exam'] = [ 'title' => $this->p->t('stv', 'tab_exam'), - 'component' => './Stv/Studentenverwaltung/Details/Pruefung.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Pruefung.js' ]; $result['exemptions'] = [ 'title' => $this->p->t('lehre', 'anrechnungen'), - 'component' => './Stv/Studentenverwaltung/Details/Anrechnungen.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Anrechnungen.js', 'config' => $config['exemptions'] ]; $result['finalexam'] = [ 'title' => $this->p->t('stv', 'tab_finalexam'), - 'component' => './Stv/Studentenverwaltung/Details/Abschlusspruefung.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Abschlusspruefung.js', 'config' => $config['finalexam'] ]; $result['mobility'] = [ 'title' => $this->p->t('stv', 'tab_mobility'), - 'component' => './Stv/Studentenverwaltung/Details/Mobility.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Mobility.js' ]; $result['archive'] = [ 'title' => $this->p->t('stv', 'tab_archive'), - 'component' => './Stv/Studentenverwaltung/Details/Archiv.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Archiv.js', 'config' => [ 'showEdit' => $this->permissionlib->isBerechtigt('admin') ] @@ -162,22 +162,22 @@ class Config extends FHCAPI_Controller $result['jointstudies'] = [ 'title' => $this->p->t('stv', 'tab_jointstudies'), - 'component' => './Stv/Studentenverwaltung/Details/JointStudies.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/JointStudies.js' ]; $result['coursedates'] = [ 'title' => $this->p->t('stv', 'tab_courseDates'), - 'component' => './Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine.js' ]; $result['admissionDates'] = [ 'title' => $this->p->t('stv', 'tab_admissionDates'), - 'component' => './Stv/Studentenverwaltung/Details/Aufnahmetermine.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Aufnahmetermine.js' ]; $result['functions'] = [ 'title' => $this->p->t('stv', 'tab_functions'), - 'component' => './Stv/Studentenverwaltung/Details/Funktionen.js' + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Funktionen.js' ]; Events::trigger('stv_conf_student', function & () use (&$result) { @@ -195,7 +195,7 @@ class Config extends FHCAPI_Controller $config = $this->config->item('tabs'); $result['banking'] = [ 'title' => $this->p->t('stv', 'tab_banking'), - 'component' => './Stv/Studentenverwaltung/Details/Konto.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Konto.js', 'config' => [ 'showZahlungsbestaetigung' => (defined('ZAHLUNGSBESTAETIGUNG_ANZEIGEN') && ZAHLUNGSBESTAETIGUNG_ANZEIGEN), 'showBuchungsnr' => $this->permissionlib->isBerechtigt('admin'), @@ -207,7 +207,7 @@ class Config extends FHCAPI_Controller ]; $result['status'] = [ 'title' => 'Status', - 'component' => './Stv/Studentenverwaltung/Details/MultiStatus.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/MultiStatus.js', 'config' => [ 'changeStatusToAbbrecherStgl' => $this->permissionlib->isBerechtigt('admin'), 'changeStatusToAbbrecherStud' => $this->permissionlib->isBerechtigt('admin'), @@ -218,12 +218,12 @@ class Config extends FHCAPI_Controller ]; $result['finalexam'] = [ 'title' => $this->p->t('stv', 'tab_finalexam'), - 'component' => './Stv/Studentenverwaltung/Details/Abschlusspruefung.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Abschlusspruefung.js', 'config' => $config['finalexam'] ]; $result['archive'] = [ 'title' => $this->p->t('stv', 'tab_archive'), - 'component' => './Stv/Studentenverwaltung/Details/Archiv.js', + 'component' => APP_ROOT . 'public/js/components/Stv/Studentenverwaltung/Details/Archiv.js', 'config' => [ 'showEdit' => $this->permissionlib->isBerechtigt('admin') ] diff --git a/application/views/Studentenverwaltung.php b/application/views/Studentenverwaltung.php index 01e611657..ebef51547 100644 --- a/application/views/Studentenverwaltung.php +++ b/application/views/Studentenverwaltung.php @@ -27,7 +27,7 @@ #'vendor/npm-asset/primevue/toast/toast.min.js' ], 'customJSModules' => [ - 'public/js/apps/Studentenverwaltung.js' + 'public/dist/js/apps/Studentenverwaltung.js' ] ); diff --git a/package.json b/package.json new file mode 100644 index 000000000..5c8cb24cf --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "fhc-core", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "rollup -c", + "watch": "rollup --watch -c" + }, + "dependencies": { + "@vuepic/vue-datepicker": "^7.2.0", + "axios": "^1.6.8", + "primevue": "^3.29.1", + "tabulator-tables": "^5.5.2", + "vue": "^3.3.8", + "vue-router": "^4.1.3" + }, + "devDependencies": { + "@rollup/plugin-alias": "^5.1.0", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "babel-plugin-transform-class-properties": "^6.24.1", + "glob": "^11.0.3", + "node-sass": "^9.0.0", + "rollup": "^4.52.4", + "rollup-plugin-postcss": "^4.0.2", + "rollup-plugin-vue": "^6.0.0" + } +} diff --git a/rollup.README.md b/rollup.README.md new file mode 100644 index 000000000..6e4c8a446 --- /dev/null +++ b/rollup.README.md @@ -0,0 +1,25 @@ +***NVM installieren*** + +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash + +oder + +wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash + +***Node.js installieren*** + +nvm install --lts + +***package.json*** + +npm install + +***Rollup build*** + +einmalig: + +npm run build + +als watch bei Änderungen: + +npm run watch diff --git a/rollup.chunks.config.js b/rollup.chunks.config.js new file mode 100644 index 000000000..58254821f --- /dev/null +++ b/rollup.chunks.config.js @@ -0,0 +1,99 @@ +import babel from '@rollup/plugin-babel'; +import nodeResolve from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import vue from "rollup-plugin-vue"; +import { globSync } from 'glob'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import postcss from 'rollup-plugin-postcss'; +import replace from '@rollup/plugin-replace'; +import alias from '@rollup/plugin-alias'; +import { existsSync } from 'node:fs'; +import terser from '@rollup/plugin-terser'; +import json from '@rollup/plugin-json'; + +function FhcResolver () { + return { + name: 'fhc-resolver', // this name will show up in logs and errors + resolveId ( source, importer, options ) { + if( source.includes('.php') ) { + return false; + } + //console.log('source: ' + source + ' options.isEntry: ' + options.isEntry + ' importer: ' + importer); + if(importer !== undefined && !options.isEntry && !path.isAbsolute(source)) { + let tmp = path.dirname(importer); + if( importer.includes('/application/') ) { + tmp = tmp.replace(/public\/js\//, 'js/').replace(/\/application\//, '/public/'); + } + const resolved = path.resolve(tmp, source); + //console.log(resolved); + if( existsSync(resolved) ) { + return resolved + } + } + return null; // other ids should be handled as usually + } + }; +} + +export default { + input: Object.fromEntries( + globSync('public/**/js/apps/**/*.js', {follow: true, realpath: true}).map(file => { + if( path.dirname(file).includes('/dist/') || path.dirname(file).includes('/apps/vbform') ) { + return null; + } + // This remove `src/` as well as the file extension from each + // file, so e.g. src/nested/foo.js becomes nested/foo + return [path.relative( + '', + file.slice(0, file.length - path.extname(file).length) + ).replace(/public\//, 'public/dist/'), + // This expands the relative paths to absolute paths, so e.g. + // src/nested/foo becomes /project/src/nested/foo.js + fileURLToPath(new URL(file, import.meta.url))] + }).filter(Boolean) + ), + plugins: [ + alias({ + entries: { + vue: 'vue/dist/vue.esm-bundler.js' + } + }), + nodeResolve({ + preferBuiltins: true, + moduleDirectories: ['node_modules'], + modulePaths: globSync('application/extensions/*/node_modules', {follow: true, realpath: true}).map(file => + fileURLToPath(new URL(file, import.meta.url)) + ), + }), + FhcResolver(), + replace({ + preventAssignment: true, + 'process.env.NODE_ENV': JSON.stringify( 'production' ), + }), + commonjs(), + vue(), + json(), + babel({ + babelHelpers: 'bundled', + plugins: ['transform-class-properties'] + }), + postcss({ + extract: false, + modules: true, + use: ['sass'], + }), + terser() + ], + watch: { + buildDelay: 500 + }, + output: { + preserveModules: false, + sourcemap: true, + format: 'es', + dir: './', + //manualChunks: {} + chunkFileNames: 'public/dist/js/includes/[name]-[hash].js' + } +}; diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 000000000..1bcc1d014 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,120 @@ +import babel from '@rollup/plugin-babel'; +import nodeResolve from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import vue from "rollup-plugin-vue"; +import { globSync } from 'glob'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import postcss from 'rollup-plugin-postcss'; +import replace from '@rollup/plugin-replace'; +import alias from '@rollup/plugin-alias'; +import { existsSync } from 'node:fs'; +import terser from '@rollup/plugin-terser'; +import json from '@rollup/plugin-json'; + +function FhcResolver () { + return { + name: 'fhc-resolver', // this name will show up in logs and errors + resolveId ( source, importer, options ) { + if( source.includes('vueDatepicker.js.php') ) { + return {id: 'vueDatepicker.js.php', external: 'relative'}; + } + if( source.includes('index.ci.php') ) { + return { id: '../' + source, external: 'relative'}; + } + if( source.includes('.php') ) { + return false; + } + //console.log('source: ' + source + ' options.isEntry: ' + options.isEntry + ' importer: ' + importer); + if(importer !== undefined && !options.isEntry && !path.isAbsolute(source)) { + let tmp = path.dirname(importer); + if( importer.includes('/application/') ) { + tmp = tmp.replace(/public\/js\//, 'js/').replace(/\/application\//, '/public/'); + } + const resolved = path.resolve(tmp, source); + //console.log(resolved); + if( existsSync(resolved) ) { + return resolved + } + } + return null; // other ids should be handled as usually + } + }; +} + +const useplugins = [ + alias({ + entries: { + vue: 'vue/dist/vue.esm-bundler.js', + } + }), + commonjs(), + nodeResolve({ + module: true, + jsnext: true, + preferBuiltins: true, + browser: true, + moduleDirectories: ['node_modules'], + modulePaths: globSync('application/extensions/*/node_modules', {follow: true, realpath: true}).map(file => + fileURLToPath(new URL(file, import.meta.url)) + ), + }), + json({ + compact: true + }), + FhcResolver(), + replace({ + preventAssignment: true, + 'process.env.NODE_ENV': JSON.stringify( 'production' ), + }), + vue(), + babel({ + babelHelpers: 'bundled', + plugins: ['transform-class-properties'], + }), +/* + postcss({ + extract: false, + modules: true, + use: ['sass'], + }), +*/ + terser() +]; + +export default globSync('public/**/js/apps/**/*.js', {follow: true, realpath: true}).map(file => { + if( path.dirname(file).includes('/dist/') || path.dirname(file).includes('/apps/vbform') ) { + return null; + } + const tmp = fileURLToPath(new URL(file, import.meta.url)); + const basepath = tmp.replace(/\/public\/js\/.*/, '/public/js/'); + const outputfile = tmp.replace(/public\//, 'public/dist/'); + let cssfile = path.basename(tmp.replace(/\.js/, '.css')); + console.log('cssfile: ' + cssfile); + let cssplugin = [ + postcss({ + extract: cssfile, + minimize: true, + sourceMap: true + }) + ]; + const vuedatepicker = path.relative(path.dirname(outputfile), basepath + 'components/vueDatepicker.js.php'); + console.log(vuedatepicker); + return { + input: tmp, + plugins: [...useplugins, ...cssplugin], + watch: { + buildDelay: 500 + }, + output: { + preserveModules: false, + inlineDynamicImports: true, + sourcemap: true, + format: 'es', + file: outputfile, + paths: { + "vueDatepicker.js.php": vuedatepicker + } + } + } + }).filter(Boolean);