Use Vite exclusively as frontend build system; remove Gulp.
This commit is contained in:
parent
49a11fb2a7
commit
53340ba20e
|
@ -89,9 +89,7 @@ jobs:
|
|||
|
||||
- name: Set console permissions and clear static assets.
|
||||
run: |
|
||||
rm -rf web/static/dist
|
||||
rm -rf web/static/vite_dist
|
||||
rm -rf web/static/assets.json
|
||||
rm -rf translations/*.UTF-8
|
||||
chmod a+x bin/console
|
||||
|
||||
|
@ -145,9 +143,7 @@ jobs:
|
|||
path: |
|
||||
.gitinfo
|
||||
translations
|
||||
web/static/dist
|
||||
web/static/vite_dist
|
||||
web/static/assets.json
|
||||
web/static/api/openapi.yml
|
||||
|
||||
build:
|
||||
|
|
|
@ -32,12 +32,8 @@ tmp/cache/*---*
|
|||
!/vendor/.gitkeep
|
||||
|
||||
# NPM built content
|
||||
/web/static/dist/*
|
||||
/web/static/dist/**/*
|
||||
!/web/static/dist/.gitkeep
|
||||
/web/static/vite_dist/**/*
|
||||
!/web/static/vite_dist/.gitkeep
|
||||
/web/static/assets.json
|
||||
/translations/frontend.pot
|
||||
|
||||
# Ansible deployment files
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
import gulp from 'gulp';
|
||||
import babel from 'gulp-babel';
|
||||
import {deleteAsync as del} from 'del';
|
||||
import rev from 'gulp-rev';
|
||||
import uglify from 'gulp-uglify';
|
||||
import gulp_sourcemaps from 'gulp-sourcemaps';
|
||||
import sass from 'gulp-dart-sass';
|
||||
import clean_css from 'gulp-clean-css';
|
||||
import revdel from 'gulp-rev-delete-original';
|
||||
import gulpmode from 'gulp-mode';
|
||||
import run_command from 'gulp-run-command';
|
||||
|
||||
const { task, src, dest, parallel, watch, series } = gulp;
|
||||
const { manifest } = rev;
|
||||
const { init, write } = gulp_sourcemaps;
|
||||
const mode = gulpmode();
|
||||
const run = run_command.default;
|
||||
|
||||
const jsFiles = {
|
||||
'bootstrap': {
|
||||
base: null,
|
||||
files: [
|
||||
'node_modules/bootstrap/dist/js/bootstrap.bundle.min.js'
|
||||
]
|
||||
},
|
||||
'material-icons': {
|
||||
files: [
|
||||
'font/*'
|
||||
]
|
||||
},
|
||||
'roboto-fontface': {
|
||||
base: 'node_modules/roboto-fontface',
|
||||
files: [
|
||||
'node_modules/roboto-fontface/css/roboto/roboto-fontface.css',
|
||||
'node_modules/roboto-fontface/fonts/roboto/*'
|
||||
]
|
||||
},
|
||||
'webcaster': {
|
||||
base: null,
|
||||
files: [
|
||||
'js/webcaster/*.js'
|
||||
]
|
||||
},
|
||||
'translations': {
|
||||
base: '../translations',
|
||||
files: [
|
||||
'../translations/*/translations.json',
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const defaultTasks = Object.keys(jsFiles);
|
||||
|
||||
defaultTasks.forEach(function (libName) {
|
||||
task('scripts:' + libName, function () {
|
||||
return src(jsFiles[libName].files, {
|
||||
base: jsFiles[libName].base
|
||||
}).pipe(dest('../web/static/dist/lib/' + libName));
|
||||
});
|
||||
});
|
||||
|
||||
task('bundle-deps', parallel(
|
||||
defaultTasks.map(function (name) {
|
||||
return 'scripts:' + name;
|
||||
})
|
||||
));
|
||||
|
||||
task('clean', function () {
|
||||
return del([
|
||||
'../web/static/dist/**/*',
|
||||
'../web/static/vite_dist/assets/**/*',
|
||||
'../web/static/vite_dist/manifest.json',
|
||||
'../web/static/assets.json',
|
||||
], {force: true});
|
||||
});
|
||||
|
||||
task('concat-js', function () {
|
||||
return src('./js/app.js')
|
||||
.pipe(init())
|
||||
.pipe(babel({
|
||||
presets: ['@babel/env']
|
||||
}))
|
||||
.pipe(uglify())
|
||||
.pipe(write())
|
||||
.pipe(dest('../web/static/dist'));
|
||||
});
|
||||
|
||||
task('build-vue', run('vite build'));
|
||||
|
||||
task('build-css', function () {
|
||||
return src(['./scss/style.scss'])
|
||||
.pipe(mode.development(init()))
|
||||
.pipe(sass({
|
||||
includePaths: ['node_modules']
|
||||
}))
|
||||
.pipe(clean_css())
|
||||
.pipe(mode.development(write()))
|
||||
.pipe(dest('../web/static/dist'));
|
||||
});
|
||||
|
||||
task('watch', function () {
|
||||
watch([
|
||||
'./vue/**',
|
||||
'./js/**/*.js',
|
||||
'./scss/**',
|
||||
], buildAll);
|
||||
});
|
||||
|
||||
const buildAll = series('clean', parallel('concat-js', 'build-vue', 'build-css', 'bundle-deps'), function () {
|
||||
return src(['../web/static/dist/**/*.{js,json,css}'], {base: '../web/static/'})
|
||||
.pipe(rev())
|
||||
.pipe(revdel())
|
||||
.pipe(dest('../web/static/'))
|
||||
.pipe(manifest('assets.json'))
|
||||
.pipe(dest('../web/static/'));
|
||||
});
|
||||
|
||||
export { buildAll as default };
|
|
@ -1,3 +1,7 @@
|
|||
import '../scss/style.scss';
|
||||
|
||||
import * as bootstrap from 'bootstrap';
|
||||
|
||||
const ready = (callback) => {
|
||||
if (document.readyState !== "loading") callback();
|
||||
else document.addEventListener("DOMContentLoaded", callback);
|
||||
|
@ -63,3 +67,5 @@ ready(() => {
|
|||
toast.show();
|
||||
});
|
||||
});
|
||||
|
||||
export default bootstrap;
|
|
@ -2,7 +2,12 @@
|
|||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["vue/*"]
|
||||
"!/*": [
|
||||
"*"
|
||||
],
|
||||
"~/*": [
|
||||
"vue/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,10 +2,8 @@
|
|||
"name": "azuracast",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"build": "gulp",
|
||||
"watch": "gulp watch",
|
||||
"generate-locales": "vue-gettext-extract",
|
||||
"vite-build": "vite build"
|
||||
"build": "vite build",
|
||||
"generate-locales": "vue-gettext-extract"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/lang-css": "^6.0.1",
|
||||
|
@ -48,8 +46,6 @@
|
|||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.5",
|
||||
"@babel/preset-env": "^7.15.6",
|
||||
"@types/luxon": "^3.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
||||
"@typescript-eslint/parser": "^6.2.1",
|
||||
|
@ -59,16 +55,6 @@
|
|||
"eslint": "^8.45.0",
|
||||
"eslint-plugin-vue": "^9.8.0",
|
||||
"glob": "^10.2.7",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-babel": "^8.0.0",
|
||||
"gulp-clean-css": "^4",
|
||||
"gulp-dart-sass": "^1.0.2",
|
||||
"gulp-mode": "^1.1.0",
|
||||
"gulp-rev": "^10",
|
||||
"gulp-rev-delete-original": "^0.2.3",
|
||||
"gulp-run-command": "0.0.10",
|
||||
"gulp-sourcemaps": "^3",
|
||||
"gulp-uglify": "^3.0.2",
|
||||
"sass": "^1.39.2",
|
||||
"typescript": "^5.1.6",
|
||||
"vite": "^4.4.6",
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
:root,
|
||||
[data-bs-theme="light"] {
|
||||
--public-page-bg: url('../img/hexbg.webp');
|
||||
--public-page-bg: url('/static/img/hexbg.webp');
|
||||
--scrollbar-color: #{$gray-400};
|
||||
}
|
||||
|
||||
@include color-mode(dark, true) {
|
||||
--public-page-bg: url('../img/hexbg_dark.webp');
|
||||
--public-page-bg: url('/static/img/hexbg_dark.webp');
|
||||
--scrollbar-color: #{$gray-800};
|
||||
--bs-info-bg-subtle: #bbdefb;
|
||||
--bs-info-text-emphasis: #181d20;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
header.navbar {
|
||||
background-image: url('../img/header_bg.webp'), linear-gradient(90deg, #0a6fc2 0%, #2196f3 100%);
|
||||
background-image: url('/static/img/header_bg.webp'), linear-gradient(90deg, #0a6fc2 0%, #2196f3 100%);
|
||||
background-position: top left, center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 500px 100px, cover;
|
||||
|
|
|
@ -1,19 +1,5 @@
|
|||
@use "sass:math";
|
||||
|
||||
@font-face {
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('lib/material-icons/material-icons.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Material Icons Outlined';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('lib/material-icons/material-icons-outlined.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@mixin reset-material-icons($size: $material-icon-size) {
|
||||
font-size: $size;
|
||||
line-height: 1;
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
@font-face {
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('../font/material-icons.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Material Icons Outlined';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('../font/material-icons-outlined.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@import "roboto-fontface/css/roboto/roboto-fontface.css";
|
||||
|
||||
// Include functions first (so you can manipulate colors, SVGs, calc, etc)
|
||||
@import "bootstrap/scss/functions";
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
@import '@vuepic/vue-datepicker/src/VueDatePicker/style/main';
|
||||
@import '@vuepic/vue-datepicker/dist/main.css';
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"!/*": [
|
||||
"*"
|
||||
],
|
||||
"~/*": [
|
||||
"vue/*"
|
||||
]
|
||||
|
@ -32,7 +35,6 @@
|
|||
"vue/**/*.ts",
|
||||
"vue/**/*.d.ts",
|
||||
"vue/**/*.tsx",
|
||||
"vue/**/*.vue",
|
||||
"vue/**/*.js"
|
||||
],
|
||||
"vue/**/*.vue"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,20 +4,26 @@ import {glob} from "glob";
|
|||
import {resolve} from "path";
|
||||
import eslint from "vite-plugin-eslint";
|
||||
|
||||
const inputs = glob.sync('./vue/pages/**/*.js').reduce((acc, path) => {
|
||||
// vue/pages/Admin/Index becomes AdminIndex
|
||||
const entry = path.replace(/\.js$/g, '')
|
||||
.replace(/^vue\/pages\//g, '')
|
||||
.replace(/\//g, '');
|
||||
|
||||
acc[entry] = resolve(__dirname, path)
|
||||
return acc
|
||||
}, {});
|
||||
|
||||
inputs['Layout'] = resolve(__dirname, './js/layout.js');
|
||||
|
||||
console.log(inputs);
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: '/static/vite_dist',
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: glob.sync('./vue/pages/**/*.js').reduce((acc, path) => {
|
||||
// vue/pages/Admin/Index becomes AdminIndex
|
||||
const entry = path.replace(/\.js$/g, '')
|
||||
.replace(/^vue\/pages\//g, '')
|
||||
.replace(/\//g, '');
|
||||
|
||||
acc[entry] = resolve(__dirname, path)
|
||||
return acc
|
||||
}, {}),
|
||||
input: inputs,
|
||||
output: {
|
||||
manualChunks: {
|
||||
vue: ['vue'],
|
||||
|
@ -28,11 +34,12 @@ export default defineConfig({
|
|||
}
|
||||
},
|
||||
manifest: true,
|
||||
emptyOutDir: false,
|
||||
emptyOutDir: true,
|
||||
outDir: resolve(__dirname, '../web/static/vite_dist')
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'!': resolve(__dirname),
|
||||
'~': resolve(__dirname, './vue')
|
||||
},
|
||||
extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json', '.vue']
|
||||
|
|
|
@ -4,7 +4,6 @@ interface AzuraCastConstants {
|
|||
locale: string,
|
||||
localeShort: string,
|
||||
localeWithDashes: string,
|
||||
localePaths: object,
|
||||
timeConfig: object,
|
||||
apiCsrf: string | null,
|
||||
enableAdvancedFeatures: boolean
|
||||
|
@ -15,7 +14,6 @@ export function useAzuraCast(): AzuraCastConstants {
|
|||
locale: App.locale ?? 'en_US',
|
||||
localeShort: App.locale_short ?? 'en',
|
||||
localeWithDashes: App.locale_with_dashes ?? 'en-US',
|
||||
localePaths: App.locale_paths ?? {},
|
||||
timeConfig: App.time_config ?? {},
|
||||
apiCsrf: App.api_csrf ?? null,
|
||||
enableAdvancedFeatures: App.enable_advanced_features ?? true
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import {createGettext, Language} from "vue3-gettext";
|
||||
import {useAzuraCast} from "~/vendor/azuracast";
|
||||
import axios from "axios";
|
||||
import {App} from "vue";
|
||||
|
||||
const {locale, localePaths} = useAzuraCast();
|
||||
const {locale} = useAzuraCast();
|
||||
|
||||
const gettext = createGettext({
|
||||
defaultLanguage: locale,
|
||||
|
@ -11,13 +10,12 @@ const gettext = createGettext({
|
|||
silent: true
|
||||
});
|
||||
|
||||
if (localePaths[locale] !== undefined) {
|
||||
axios.get(
|
||||
localePaths[locale]
|
||||
).then(r => {
|
||||
gettext.translations = r.data;
|
||||
}).catch((e) => {
|
||||
console.error(e);
|
||||
const translations = import.meta.glob('../../../translations/**/translations.json', {as: 'json'});
|
||||
const localePath = '../../../translations/' + locale + '.UTF-8/translations.json';
|
||||
|
||||
if (localePath in translations) {
|
||||
translations[localePath]().then((data) => {
|
||||
gettext.translations = data;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
24
src/View.php
24
src/View.php
|
@ -70,9 +70,7 @@ final class View extends Engine
|
|||
$vueComponents = Json::loadFromFile($environment->getBaseDirectory() . '/web/static/vite_dist/manifest.json');
|
||||
$this->registerFunction(
|
||||
'getVueComponentInfo',
|
||||
function (string $component) use ($vueComponents) {
|
||||
$componentPath = 'vue/pages/' . $component . '.js';
|
||||
|
||||
function (string $componentPath) use ($vueComponents) {
|
||||
if (!isset($vueComponents[$componentPath])) {
|
||||
return null;
|
||||
}
|
||||
|
@ -125,26 +123,6 @@ final class View extends Engine
|
|||
}
|
||||
);
|
||||
|
||||
$versionedFiles = Json::loadFromFile($environment->getBaseDirectory() . '/web/static/assets.json');
|
||||
$this->registerFunction(
|
||||
'assetUrl',
|
||||
function (string $url) use ($environment, $versionedFiles): string {
|
||||
if (isset($versionedFiles[$url])) {
|
||||
$url = $versionedFiles[$url];
|
||||
}
|
||||
|
||||
if (str_starts_with($url, 'http')) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
if (str_starts_with($url, '/')) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
return $environment->getAssetUrl() . '/' . $url;
|
||||
}
|
||||
);
|
||||
|
||||
$dispatcher->dispatch(new Event\BuildView($this));
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ $this->fetch('frontend/public/partials/station-custom', ['station' => $station])
|
|||
|
||||
$sections->appendStart('bodyjs');
|
||||
?>
|
||||
<script src="<?= $this->assetUrl('dist/lib/webcaster/taglib.js') ?>"></script>
|
||||
<script src="/static/js/taglib.js"></script>
|
||||
<?php
|
||||
$sections->end();
|
||||
|
||||
|
|
|
@ -22,17 +22,6 @@ if (null !== $show24Hours) {
|
|||
$timeConfig->hour12 = !$show24Hours;
|
||||
}
|
||||
|
||||
$localePaths = [];
|
||||
foreach (App\Enums\SupportedLocales::cases() as $supportedLocale) {
|
||||
if ($supportedLocale === App\Enums\SupportedLocales::default()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$localePaths[$supportedLocale->getLocaleWithoutEncoding()] = $this->assetUrl(
|
||||
'dist/lib/translations/' . $supportedLocale->value . '/translations.json'
|
||||
);
|
||||
}
|
||||
|
||||
// CSRF token
|
||||
$csrf = null;
|
||||
|
||||
|
@ -47,7 +36,6 @@ $app = [
|
|||
'locale' => $locale,
|
||||
'locale_short' => $localeShort,
|
||||
'locale_with_dashes' => $localeWithDashes,
|
||||
'locale_paths' => $localePaths,
|
||||
'time_config' => $timeConfig,
|
||||
'api_csrf' => $csrf,
|
||||
'enable_advanced_features' => $customization->enableAdvancedFeatures(),
|
||||
|
|
|
@ -3,14 +3,31 @@
|
|||
* @var App\Customization $customization
|
||||
*/
|
||||
|
||||
$componentDeps = $this->getVueComponentInfo('js/layout.js');
|
||||
|
||||
echo <<<HTML
|
||||
<script type="module" src="{$componentDeps['js']}"></script>
|
||||
<script>
|
||||
function ready(callback) {
|
||||
if (document.readyState !== "loading") callback();
|
||||
else document.addEventListener("DOMContentLoaded", callback);
|
||||
}
|
||||
</script>
|
||||
HTML;
|
||||
|
||||
foreach ($componentDeps['prefetch'] as $prefetchDep) {
|
||||
echo <<<HTML
|
||||
<link rel="modulepreload" href="{$prefetchDep}" />
|
||||
HTML;
|
||||
}
|
||||
|
||||
foreach ($componentDeps['css'] as $cssDep) {
|
||||
echo <<<HTML
|
||||
<link rel="stylesheet" href="{$cssDep}" />
|
||||
HTML;
|
||||
}
|
||||
?>
|
||||
|
||||
<script src="<?= $this->assetUrl('dist/lib/bootstrap/bootstrap.bundle.min.js') ?>"></script>
|
||||
<script src="<?= $this->assetUrl('dist/app.js') ?>"></script>
|
||||
|
||||
<link rel="stylesheet" href="<?= $this->assetUrl('dist/lib/roboto-fontface/css/roboto/roboto-fontface.css') ?>">
|
||||
<link rel="stylesheet" href="<?= $this->assetUrl('dist/style.css') ?>">
|
||||
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="<?= $customization->getBrowserIconUrl(57) ?>">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="<?= $customization->getBrowserIconUrl(60) ?>">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="<?= $customization->getBrowserIconUrl(72) ?>">
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* @var App\View\GlobalSections $sections
|
||||
*/
|
||||
|
||||
$componentDeps = $this->getVueComponentInfo($component);
|
||||
$componentDeps = $this->getVueComponentInfo('vue/pages/' . $component . '.js');
|
||||
|
||||
$propsJson = json_encode($props, JSON_THROW_ON_ERROR);
|
||||
|
||||
|
|
|
@ -110,9 +110,6 @@ server {
|
|||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location /static/dist {
|
||||
expires 365d;
|
||||
}
|
||||
location /static/vite_dist {
|
||||
expires 365d;
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
.gitkeep
|
|
@ -1 +0,0 @@
|
|||
.gitkeep
|
Loading…
Reference in New Issue