diff --git a/Makefile b/Makefile index 2a08c7633..45e07364d 100644 --- a/Makefile +++ b/Makefile @@ -107,7 +107,7 @@ endif GO_SOURCES_OWN := $(filter-out vendor/% %/bindata.go, $(GO_SOURCES)) -FOMANTIC_CONFIGS := semantic.json web_src/fomantic/theme.config.less web_src/fomantic/_site/globals/site.variables +FOMANTIC_CONFIGS := semantic.json web_src/fomantic/theme.config.less web_src/fomantic/_site/globals/site.variables web_src/fomantic/css.js FOMANTIC_DEST := public/fomantic/semantic.min.js public/fomantic/semantic.min.css FOMANTIC_DEST_DIR := public/fomantic @@ -589,7 +589,8 @@ fomantic: $(FOMANTIC_DEST) $(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) package-lock.json | node_modules rm -rf $(FOMANTIC_DEST_DIR) cp web_src/fomantic/theme.config.less node_modules/fomantic-ui/src/theme.config - cp web_src/fomantic/_site/globals/* node_modules/fomantic-ui/src/_site/globals/ + cp -r web_src/fomantic/_site/* node_modules/fomantic-ui/src/_site/ + cp web_src/fomantic/css.js node_modules/fomantic-ui/tasks/build/css.js npx gulp -f node_modules/fomantic-ui/gulpfile.js build @touch $(FOMANTIC_DEST) @@ -654,4 +655,4 @@ golangci-lint: golangci-lint run --timeout 5m # This endif closes the if at the top of the file -endif \ No newline at end of file +endif diff --git a/package-lock.json b/package-lock.json index 9169f83a8..1c10bac38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2910,50 +2910,6 @@ } } }, - "copy-webpack-plugin": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz", - "integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==", - "requires": { - "cacache": "^12.0.3", - "find-cache-dir": "^2.1.0", - "glob-parent": "^3.1.0", - "globby": "^7.1.1", - "is-glob": "^4.0.1", - "loader-utils": "^1.2.3", - "minimatch": "^3.0.4", - "normalize-path": "^3.0.0", - "p-limit": "^2.2.1", - "schema-utils": "^1.0.0", - "serialize-javascript": "^2.1.2", - "webpack-log": "^2.0.0" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, "core-js": { "version": "3.6.5", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", @@ -3620,14 +3576,6 @@ "randombytes": "^2.0.0" } }, - "dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "requires": { - "path-type": "^3.0.0" - } - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -5926,26 +5874,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, - "globby": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", - "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", - "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } - } - }, "globjoin": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", @@ -7289,11 +7217,6 @@ "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" - }, "image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", @@ -9945,21 +9868,6 @@ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } - } - }, "pbkdf2": { "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", @@ -12371,11 +12279,6 @@ } } }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -14483,7 +14386,8 @@ "uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "optional": true }, "v-tooltip": { "version": "2.0.3", @@ -15125,15 +15029,6 @@ "resolved": "https://registry.npmjs.org/webpack-fix-style-only-entries/-/webpack-fix-style-only-entries-0.4.0.tgz", "integrity": "sha512-6TDa56V/xSOw6CBVlhFm6J+xXY2oJzx7CEgH0dmex2Xe1rwb95KkLl3rXvSNpO4wyahwD3YnYqffDNR0LH1BNQ==" }, - "webpack-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", - "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - } - }, "webpack-sources": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", diff --git a/package.json b/package.json index ec661a90b..d520fa38a 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "@primer/octicons": "9.6.0", "babel-loader": "8.1.0", "clipboard": "2.0.6", - "copy-webpack-plugin": "5.1.1", "core-js": "3.6.5", "css-loader": "3.5.2", "cssnano": "4.1.10", diff --git a/web_src/fomantic/css.js b/web_src/fomantic/css.js new file mode 100644 index 000000000..2d753f061 --- /dev/null +++ b/web_src/fomantic/css.js @@ -0,0 +1,260 @@ +/******************************* + * Build Task + *******************************/ + +const + gulp = require('gulp'), + + // node dependencies + console = require('better-console'), + + // gulp dependencies + autoprefixer = require('gulp-autoprefixer'), + chmod = require('gulp-chmod'), + concatCSS = require('gulp-concat-css'), + dedupe = require('gulp-dedupe'), + flatten = require('gulp-flatten'), + gulpif = require('gulp-if'), + header = require('gulp-header'), + less = require('gulp-less'), + minifyCSS = require('gulp-clean-css'), + normalize = require('normalize-path'), + plumber = require('gulp-plumber'), + print = require('gulp-print').default, + rename = require('gulp-rename'), + replace = require('gulp-replace'), + replaceExt = require('replace-ext'), + rtlcss = require('gulp-rtlcss'), + + // config + config = require('./../config/user'), + docsConfig = require('./../config/docs'), + tasks = require('../config/tasks'), + install = require('../config/project/install'), + + // shorthand + globs = config.globs, + assets = config.paths.assets, + + banner = tasks.banner, + filenames = tasks.filenames, + comments = tasks.regExp.comments, + log = tasks.log, + settings = tasks.settings +; + +/** + * Builds the css + * @param src + * @param type + * @param compress + * @param config + * @param opts + * @return {*} + */ +function build(src, type, compress, config, opts) { + let fileExtension; + if (type === 'rtl' && compress) { + fileExtension = settings.rename.rtlMinCSS; + } else if (type === 'rtl') { + fileExtension = settings.rename.rtlCSS; + } else if (compress) { + fileExtension = settings.rename.minCSS; + } + + return gulp.src(src, opts) + .pipe(plumber(settings.plumber.less)) + .pipe(less(settings.less)) + .pipe(autoprefixer(settings.prefix)) + .pipe(gulpif(type === 'rtl', rtlcss())) + .pipe(replace(comments.variables.in, comments.variables.out)) + .pipe(replace(comments.license.in, comments.license.out)) + .pipe(replace(comments.large.in, comments.large.out)) + .pipe(replace(comments.small.in, comments.small.out)) + .pipe(replace(comments.tiny.in, comments.tiny.out)) + .pipe(flatten()) + .pipe(replace(config.paths.assets.source, + compress ? config.paths.assets.compressed : config.paths.assets.uncompressed)) + .pipe(gulpif(compress, minifyCSS(settings.minify))) + .pipe(gulpif(fileExtension, rename(fileExtension))) + .pipe(gulpif(config.hasPermissions, chmod(config.parsedPermissions))) + .pipe(gulp.dest(compress ? config.paths.output.compressed : config.paths.output.uncompressed)) + .pipe(print(log.created)) + ; +} + +/** + * Packages the css files in dist + * @param {string} type - type of the css processing (none, rtl, docs) + * @param {boolean} compress - should the output be compressed + */ +function pack(type, compress) { + const output = type === 'docs' ? docsConfig.paths.output : config.paths.output; + const ignoredGlobs = type === 'rtl' ? globs.ignoredRTL + '.rtl.css' : globs.ignored + '.css'; + + let concatenatedCSS; + if (type === 'rtl') { + concatenatedCSS = compress ? filenames.concatenatedMinifiedRTLCSS : filenames.concatenatedRTLCSS; + } else { + concatenatedCSS = compress ? filenames.concatenatedMinifiedCSS : filenames.concatenatedCSS; + } + + return gulp.src(output.uncompressed + '/**/' + globs.components + ignoredGlobs) + .pipe(plumber()) + .pipe(dedupe()) + .pipe(replace(assets.uncompressed, assets.packaged)) + .pipe(concatCSS(concatenatedCSS, settings.concatCSS)) + .pipe(gulpif(config.hasPermissions, chmod(config.parsedPermissions))) + .pipe(gulpif(compress, minifyCSS(settings.concatMinify))) + .pipe(header(banner, settings.header)) + .pipe(gulp.dest(output.packaged)) + .pipe(print(log.created)) + ; +} + +function buildCSS(src, type, config, opts, callback) { + if (!install.isSetup()) { + console.error('Cannot build CSS files. Run "gulp install" to set-up Semantic'); + callback(); + return; + } + + if (callback === undefined) { + callback = opts; + opts = config; + config = type; + type = src; + src = config.paths.source.definitions + '/**/' + config.globs.components + '.less'; + } + + const buildUncompressed = () => build(src, type, false, config, opts); + buildUncompressed.displayName = 'Building uncompressed CSS'; + + const buildCompressed = () => build(src, type, true, config, opts); + buildCompressed.displayName = 'Building compressed CSS'; + + const packUncompressed = () => pack(type, false); + packUncompressed.displayName = 'Packing uncompressed CSS'; + + const packCompressed = () => pack(type, true); + packCompressed.displayName = 'Packing compressed CSS'; + + gulp.parallel( + gulp.series( + buildUncompressed, + gulp.parallel(packUncompressed, packCompressed) + ), + gulp.series(buildCompressed) + )(callback); +} + +function rtlAndNormal(src, callback) { + if (callback === undefined) { + callback = src; + src = config.paths.source.definitions + '/**/' + config.globs.components + '.less'; + } + + const rtl = (callback) => buildCSS(src, 'rtl', config, {}, callback); + rtl.displayName = "CSS Right-To-Left"; + const css = (callback) => buildCSS(src, 'default', config, {}, callback); + css.displayName = "CSS"; + + if (config.rtl === true || config.rtl === 'Yes') { + rtl(callback); + } else if (config.rtl === 'both') { + gulp.series(rtl, css)(callback); + } else { + css(callback); + } +} + +function docs(src, callback) { + if (callback === undefined) { + callback = src; + src = config.paths.source.definitions + '/**/' + config.globs.components + '.less'; + } + + const func = (callback) => buildCSS(src, 'docs', config, {}, callback); + func.displayName = "CSS Docs"; + + func(callback); +} + +// Default tasks +module.exports = rtlAndNormal; + +// We keep the changed files in an array to call build with all of them at the same time +let timeout, files = []; + +/** + * Watch changes in CSS files and call the correct build pipe + * @param type + * @param config + */ +module.exports.watch = function (type, config) { + const method = type === 'docs' ? docs : rtlAndNormal; + + // Watch theme.config file + gulp.watch([ + normalize(config.paths.source.config), + normalize(config.paths.source.site + '/**/site.variables'), + normalize(config.paths.source.themes + '/**/site.variables') + ]) + .on('all', function () { + // Clear timeout and reset files + timeout && clearTimeout(timeout); + files = []; + return gulp.series(method)(); + }); + + // Watch any less / overrides / variables files + gulp.watch([ + normalize(config.paths.source.definitions + '/**/*.less'), + normalize(config.paths.source.site + '/**/*.{overrides,variables}'), + normalize(config.paths.source.themes + '/**/*.{overrides,variables}') + ]) + .on('all', function (event, path) { + // We don't handle deleted files yet + if (event === 'unlink' || event === 'unlinkDir') { + return; + } + + // Clear timeout + timeout && clearTimeout(timeout); + + // Determine which LESS file has to be recompiled + let lessPath; + if(path.indexOf('site.variables') !== -1) { + return; + } else if (path.indexOf(config.paths.source.themes) !== -1) { + console.log('Change detected in packaged theme'); + lessPath = replaceExt(path, '.less'); + lessPath = lessPath.replace(tasks.regExp.theme, config.paths.source.definitions); + } else if (path.indexOf(config.paths.source.site) !== -1) { + console.log('Change detected in site theme'); + lessPath = replaceExt(path, '.less'); + lessPath = lessPath.replace(config.paths.source.site, config.paths.source.definitions); + } else { + console.log('Change detected in definition'); + lessPath = path; + } + + // Add file to internal changed files array + if (!files.includes(lessPath)) { + files.push(lessPath); + } + + // Update timeout + timeout = setTimeout(() => { + // Copy files to build in another array + const buildFiles = [...files]; + // Call method + gulp.series((callback) => method(buildFiles, callback))(); + // Reset internal changed files array + files = []; + }, 1000); + }); +}; + +// Expose build css method +module.exports.buildCSS = buildCSS; diff --git a/webpack.config.js b/webpack.config.js index 77680cb37..e87dd770c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,5 @@ const cssnano = require('cssnano'); const fastGlob = require('fast-glob'); -const CopyPlugin = require('copy-webpack-plugin'); const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); @@ -210,10 +209,6 @@ module.exports = { new SpriteLoaderPlugin({ plainSprite: true, }), - new CopyPlugin([ - // workaround for https://github.com/go-gitea/gitea/issues/10653 - {from: 'node_modules/fomantic-ui/dist/semantic.min.css', to: 'fomantic/semantic.min.css'}, - ]), ], performance: { hints: false,