Frontent dev env (#247)

* Added frontend development files/environment

* More items-categories related removals

* Improvements in pages templates (inc. static pages)

* Improvements in video player

* Added empty home page message + cta

* Updates in media, playlist and management pages

* Improvements in material icons font loading

* Replaced media & playlists links in frontend dev-env

* frontend package version update

* chnaged frontend dev url port

* static files update

* Changed default position of theme switcher

* enabled frontend docker container
This commit is contained in:
Yiannis Stergiou
2021-07-11 18:01:34 +03:00
committed by GitHub
parent 060bb45725
commit aa6520daac
555 changed files with 201927 additions and 66002 deletions

View File

@@ -0,0 +1,69 @@
const merge = require('lodash.merge');
import { ConfigHtml, ConfigPages, ConfigWindow } from '../config';
function validateBoolean(value?: boolean | 0 | 1, defaultValue = false): boolean {
if (true === value || false === value) {
return value;
}
if (0 === value || 1 === value) {
return !!value;
}
return defaultValue;
}
function validateString(value?: string, defaultValue = ''): string {
return value ? value : defaultValue;
}
function getArrayType(sourcesArr?: Array<{ [key: string]: string }>, pageArr: Array<{ [key: string]: string }> = []): Array<{ [key: string]: string }> {
if ((!sourcesArr || !sourcesArr.length) && (!pageArr || !pageArr.length)) {
return [];
}
if (sourcesArr && sourcesArr.length && pageArr && pageArr.length) {
return sourcesArr.concat(pageArr);
}
if (sourcesArr && sourcesArr.length) {
return sourcesArr;
}
return pageArr;
}
function formatPagesConfig(sources: { title: string, filename: string, render: string, html: ConfigHtml, window: ConfigWindow }, pages: ConfigPages): ConfigPages {
const ret: ConfigPages = {};
for (const pk in pages) {
ret[pk] = {
staticPage: validateBoolean(pages[pk].staticPage, false),
buildExclude: validateBoolean(pages[pk].buildExclude, false),
title: validateString(pages[pk].title, sources.title),
filename: validateString(pages[pk].filename, sources.filename),
html: {
head: {
meta: getArrayType(sources.html.head.meta, pages[pk].html.head.meta),
links: getArrayType(sources.html.head.links, pages[pk].html.head.links),
scripts: getArrayType(sources.html.head.scripts, pages[pk].html.head.scripts),
},
body: {
scripts: getArrayType(sources.html.body.scripts, pages[pk].html.body.scripts),
snippet: validateString(pages[pk].html.body.snippet, sources.html.body.snippet),
},
},
window: merge({}, sources.window, pages[pk].window),
render: validateString(sources.render, pages[pk].render),
};
}
return ret;
}
export default formatPagesConfig;

View File

@@ -0,0 +1,308 @@
const path = require('path');
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
// Webpack plugins.
const { DefinePlugin } = require('webpack');
const { LimitChunkCountPlugin } = require('webpack').optimize;
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VirtualModulesPlugin = require('webpack-virtual-modules');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const CopyPlugin = require("copy-webpack-plugin");
var dotenv = require('dotenv').config({ path: path.resolve(__dirname + '../../../../.env') });
import MyHtmlBeautifyWebpackPlugin from '../webpack-plugins/MyHtmlBeautifyWebpackPlugin';
import { ConfigType, ConfigPages } from '../config';
import defaultPages from './pagesConfig';
import formatPagesConfig from './formatPagesConfig';
function webpackEntry(env: string, srcDir: string, pages: ConfigPages) {
const ret: { [key: string]: string } = {};
for (const p in pages) {
if ('development' === env || !pages[p].buildExclude) {
ret[p] = path.resolve(srcDir + '/' + p + '.js');
}
}
return ret;
}
function webpackOutput(env: string, destinationDir: string, buildDir?: string, chunkhash?: string, hash?: string) {
const ret = {
path: destinationDir,
filename: '',
};
const prefix = 'development' === env ? '' : buildDir;
let tmp;
if (undefined !== chunkhash) {
tmp = chunkhash.trim();
if ('' === tmp) {
throw Error('Invalid chunkhash argument value: ' + chunkhash);
}
ret.filename = (prefix || '') + '[name]-[chunkhash].js';
}
else if (undefined !== hash) {
tmp = hash.trim();
if ('' === tmp) {
throw Error('Invalid hash argument value: ' + hash);
}
ret.filename = (prefix || '') + '[name]-[hash].js';
}
else {
ret.filename = (prefix || '') + '[name].js';
}
return ret;
}
function webpackAlias() {
return {
// modernizr$: path.resolve(__dirname, "../../.modernizrrc"), // TODO: Enable this?
};
}
function webpackRules(env: string, srcDir: string, postcssConfigFile: string): any[] {
return [{
test: /\.(jsx|js)?$/,
use: 'babel-loader'
},
{
test: /\.(tsx|ts)?$/,
use: 'ts-loader',
// exclude: /node_modules/,
// options: {
// compilerOptions: {
// "sourceMap": !isProduction,
// },
// },
},
{
test: /\.ejs$/,
use: {
loader: 'ejs-compiled-loader',
options: {
// beautify: true,
htmlmin: true,
// htmlminOptions: {
// removeComments: true,
// collapseWhitespace: true,
// preserveLineBreaks: true
// }
}
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{ loader: MiniCssExtractPlugin.loader },
// { loader: 'development' === env ? MiniCssExtractPlugin.loader : 'style-loader' }, // Use inline <style> tag.
{ loader: 'css-loader', options: { importLoaders: 1 } },
{ loader: 'postcss-loader', options: { postcssOptions: { config: postcssConfigFile } } },
{ loader: 'sass-loader' },
],
},
{
test: /\.module\.(sa|sc|c)ss$/,
use: [
{ loader: MiniCssExtractPlugin.loader },
// { loader: 'development' === env ? MiniCssExtractPlugin.loader : 'style-loader' }, // Use inline <style> tag.
{ loader: 'css-loader', options: { importLoaders: 1, modules: true, onlyLocals: false } },
{ loader: 'postcss-loader', options: { postcssOptions: { config: postcssConfigFile } } },
{ loader: 'sass-loader' },
]
},
{
test: /\.(png|jpe?g|gif)(\?\S*)?$/,
use: {
loader: 'url-loader',
options: {
limit: 1024,
fallback: 'file-loader',
name: (file: string) => {
return '.' + path.join(file.replace(srcDir, ''), '..').replace(/\\/g, '/') + '/[name].[ext]';
},
},
},
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
/*issuer: {
test: /\.jsx?$/
},*/
use: ['babel-loader', '@svgr/webpack', 'url-loader']
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader'
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'file-loader',
options: {
name: (file: string) => {
return '.' + path.join(file.replace(srcDir, ''), '..').replace(/\\/g, '/') + '/[name].[ext]';
},
}
}]
},
{
test: /\.modernizrrc.js$/,
use: 'modernizr-loader',
},
{
test: /\.modernizrrc(\.json)?$/,
use: ['modernizr-loader', 'json-loader'],
}
];
}
function webpackPlugins(env: string, srcDir: string, pages: ConfigPages, cssSrc: string) {
const ret = [
new DefinePlugin({ "process.env": JSON.stringify(dotenv.parsed) }),
new NodePolyfillPlugin(),
new MyHtmlBeautifyWebpackPlugin(),
];
if ('development' !== env) {
ret.push(
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, '../../../src/static/lib'),
to: path.resolve(__dirname, '../../../' + env + '/static/lib'),
},
{
from: path.resolve(__dirname, '../../../src/static/images'),
to: path.resolve(__dirname, '../../../' + env + '/static/images'),
},
{
from: path.resolve(__dirname, '../../../src/static/favicons'),
to: path.resolve(__dirname, '../../../' + env + '/static/favicons'),
},
{
from: path.resolve(__dirname, '../../../src/static/css/_extra.css'),
to: path.resolve(__dirname, '../../../' + env + '/static/css/_extra.css'),
},
],
})
);
}
const virtualPages: { [key: string]: string } = {};
let file: string;
for (const k in pages) {
if ('production' !== env || !pages[k].buildExclude) {
file = path.resolve(srcDir + '/' + k + '.js');
if ((void 0 !== pages[k].staticPage && pages[k].staticPage) || void 0 === pages[k].render) {
virtualPages[file] = '';
} else {
virtualPages[file] = pages[k].render;
}
}
if ('development' === env) {
// Export pages HTML files.
ret.push(new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../templates/index.ejs'),
hash: false,
chunks: [k],
...pages[k],
}));
}
}
ret.push(new VirtualModulesPlugin(virtualPages));
ret.push(new MiniCssExtractPlugin({
ignoreOrder: true, // TODO: Remove it...
// filename: ! is_build ? '[name].css' : '[name].[hash].css',
// chunkFilename: ! is_build ? '[id].css' : '[id].[hash].css',
filename: cssSrc + '[name].css',
// chunkFilename: "../css/[id].css",
}));
if ('development' !== env) {
ret.push(new LimitChunkCountPlugin({ maxChunks: 1 }));
ret.push(
new ProgressBarPlugin({
clear: false,
})
);
}
if ('production' === env) {
ret.push(new CssMinimizerPlugin({
cache: true, // TODO: Ignore in Webpack 5. Use https://webpack.js.org/configuration/other-options/#cache.
minimizerOptions: {
preset: [
'default',
{
discardComments: { removeAll: true },
},
],
},
}));
}
return ret;
}
export default function generateConfig(env: string, config: ConfigType) {
const srcDir = config.src;
const buildDir = config.build + '/' + env + ('development' === env ? '' : '/static');
const cssbuild = './css/';
const jsbuild = './js/';
const configPages = config.pages;
const configPagesKeys = config.pages ? Object.keys(configPages) : [];
const defPages = defaultPages(configPagesKeys);
const pages = formatPagesConfig(
{ title: '', filename: '', render: '', html: config.html, window: config.window },
{ ...configPages, ...defPages }
);
const ret = {
entry: webpackEntry(env, srcDir, pages),
output: 'development' === env ? webpackOutput(env, srcDir, void 0, void 0, void 0) : webpackOutput(env, buildDir, jsbuild, void 0, void 0),
plugins: webpackPlugins(env, srcDir, pages, cssbuild),
module: {
rules: webpackRules(env, srcDir, config.postcssConfigFile),
},
resolve: {
alias: webpackAlias(),
extensions: ['.tsx', '.ts', '.jsx', '.js'],
},
};
return ret;
}

View File

@@ -0,0 +1,37 @@
const fs = require('fs');
const path = require('path');
const ejs = require('ejs');
const templatePath = path.join(__dirname, '../templates');
const sitemapTemplatePath = path.join(templatePath, 'sitemap.ejs');
const sitemapTemplate = ejs.compile(fs.readFileSync(sitemapTemplatePath, 'utf8'), { root: [templatePath], filename: sitemapTemplatePath, outputFunctionName: 'echo' });
import { ConfigPages } from '../config';
export default function pagesConfig(pagesKeys: string[]): ConfigPages {
const pages: ConfigPages = {};
if (-1 === pagesKeys.indexOf('sitemap')) {
pages.sitemap = {
staticPage: true,
buildExclude: true,
title: 'Sitemap',
filename: 'sitemap.html',
html: {
head: {},
body: {
scripts: [],
snippet: sitemapTemplate({ pages: [...pagesKeys, ...Object.keys(pages)] }),
},
},
window: {},
render: ''
};
}
return pages;
}