Skip to content
Snippets Groups Projects

Replace ruby-sass with dart-sass (node)

Merged Muhammed Ali requested to merge gitlab-community/gitlab:replace-sass into master
2 unresolved threads
1 file
+ 43
100
Compare changes
  • Side-by-side
  • Inline
+ 43
100
import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from 'fs';
import path from 'path';
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import { compile } from 'sass';
import glob from 'glob';
/* eslint-disable import/extensions */
import IS_EE from '../../config/helpers/is_ee_env.js';
import IS_JH from '../../config/helpers/is_jh_env.js';
/* eslint-enable import/extensions */
const OUTPUT_PATH = 'app/assets/builds/';
const ROOT_PATH = new URL('../../', import.meta.url);
const ROOT_PATH = new URL('../../', import.meta.url).pathname;
const BASE_PATH = 'app/assets/stylesheets';
const EE_BASE_PATH = 'ee/app/assets/stylesheets';
function resolveLoadPaths() {
const loadPaths = {
base: ['app/assets/stylesheets'],
base: [BASE_PATH],
vendor: [
// no-op files
'app/assets/stylesheets/_ee',
@@ -23,7 +27,7 @@ function resolveLoadPaths() {
};
if (IS_EE) {
loadPaths.base.unshift('ee/app/assets/stylesheets');
loadPaths.base.unshift(EE_BASE_PATH);
loadPaths.vendor.unshift('ee/app/assets/stylesheets/_ee');
}
if (IS_JH) {
@@ -32,7 +36,7 @@ function resolveLoadPaths() {
}
return Object.values(loadPaths)
.flat()
.map((p) => path.resolve(ROOT_PATH.pathname, p));
.map((p) => path.resolve(ROOT_PATH, p));
}
const SASS_LOAD_PATHS = resolveLoadPaths();
@@ -43,122 +47,61 @@ const defaultOptions = {
// Source => Destination (Relative to OUTPUT_PATH)
const inputFiles = new Map([
['app/assets/stylesheets/application.scss', 'application.css'],
['app/assets/stylesheets/application_dark.scss', 'application_dark.css'],
['app/assets/stylesheets/application_utilities.scss', 'application_utilities.css'],
['app/assets/stylesheets/application_utilities_dark.scss', 'application_utilities_dark.css'],
['app/assets/stylesheets/disable_animations.scss', 'disable_animations.css'],
['app/assets/stylesheets/emoji_sprites.scss', 'emoji_sprites.css'],
['app/assets/stylesheets/errors.scss', 'errors.css'],
['app/assets/stylesheets/fonts.scss', 'fonts.css'],
['app/assets/stylesheets/mailer.scss', 'mailer.css'],
['app/assets/stylesheets/mailer_client_specific.scss', 'mailer_client_specific.css'],
['app/assets/stylesheets/notify.scss', 'notify.css'],
['app/assets/stylesheets/notify_enhanced.scss', 'notify_enhanced.css'],
['app/assets/stylesheets/performance_bar.scss', 'performance_bar.css'],
['app/assets/stylesheets/print.scss', 'print.css'],
['app/assets/stylesheets/snippets.scss', 'snippets.css'],
['app/assets/stylesheets/test_environment.scss', 'test_environment.css'],
['app/assets/stylesheets/lazy_bundles/', 'lazy_bundles/'],
['app/assets/stylesheets/mailers/', 'mailers/'],
[
'app/assets/stylesheets/page_bundles/_mixins_and_variables_and_functions.scss',
'page_bundles/_mixins_and_variables_and_functions.css',
],
['app/assets/stylesheets/page_bundles/', 'page_bundles/'],
['app/assets/stylesheets/themes/_dark.scss', 'themes/_dark.css'], // TODO: find out why this is explicitly compiled
['app/assets/stylesheets/themes/', 'themes/'],
[
'app/assets/stylesheets/highlight/diff_custom_colors_addition.scss',
'highlight/diff_custom_colors_addition.css',
'app/assets/stylesheets/**/*.scss',
{
ignore: [
'**/_*.scss',
'**/{_*,framework,components,pages,vendors}/**',
'**/bootstrap_migration*', // TODO: Prefix file name with _ (and/or move to framework)
'**/highlight/conflict_colors.scss', // TODO: Prefix file name with _
'**/highlight/white_base.scss', // TODO: Prefix file name with _
'**/utilities.scss', // TODO: Prefix file name with _
],
},
],
[
'app/assets/stylesheets/highlight/diff_custom_colors_deletion.scss',
'highlight/diff_custom_colors_deletion.css',
],
['app/assets/stylesheets/highlight/themes/', 'highlight/themes/'],
['app/assets/stylesheets/page_bundles/_mixins_and_variables_and_functions.scss'],
['app/assets/stylesheets/themes/_dark.scss'], // TODO: find out why this is explicitly compiled
]);
if (IS_EE) {
inputFiles.set('ee/app/assets/stylesheets/page_bundles/', 'page_bundles/');
inputFiles.set('ee/app/assets/stylesheets/page_bundles/**/*.scss', {
ignore: ['_*.scss'],
basePath: EE_BASE_PATH,
});
}
function writeContentToFile(content, src, dest) {
const destPath = path.resolve(ROOT_PATH.pathname, dest);
let outputFile;
if (src.relativePath) {
outputFile = path.resolve(destPath, src.relativePath);
console.log('Outputting to: ', outputFile, path.extname(outputFile));
if (path.extname(outputFile) === '.scss') {
outputFile = outputFile.replace(/\.[^.]+$/, '.css');
}
} else {
outputFile = destPath;
}
console.log(`Writing ${src.fullPath} to ${outputFile}`);
function writeContentToFile(content, src, outputFile) {
console.log(`Writing ${content.fullPath} to ${outputFile}`);
if (!existsSync(path.dirname(outputFile))) {
mkdirSync(path.dirname(outputFile), { recursive: true });
}
writeFileSync(outputFile, content.css);
}
function resolveSources(base, source, dest) {
console.log('Resolving source', source);
const destPath = path.resolve(base, dest);
const fullPath = path.resolve(base, source);
function resolveSources(rootPath, globPath, options = {}) {
const { ignore = [], basePath = BASE_PATH } = options;
console.log('Resolving source', globPath);
// If single scss file, then return single object
if (statSync(fullPath).isFile() && path.extname(source) === '.scss') {
console.log('Source is a file, Dest is: ', dest, fullPath);
return [{ source, dest: destPath }];
}
const paths = new Set();
const scssPaths = path.join(ROOT_PATH, globPath);
if (statSync(fullPath).isDirectory()) {
// Filter out any scss files that start with _
// Only keep files and directories
readdirSync(fullPath)
.filter(
(f) =>
statSync(path.resolve(fullPath, f)).isDirectory() ||
(f.endsWith('.scss') && !f.startsWith('_')),
)
.forEach((relativeFile) => {
// Full Path to each immediate item in this directory
const file = path.resolve(fullPath, relativeFile);
console.log('resolved file: ', file);
return glob.sync(scssPaths, { ignore }).map((sourceFile) => {
const relSourcePath = path.relative(path.join(ROOT_PATH, basePath), sourceFile);
const destFile = path.join(rootPath, OUTPUT_PATH, relSourcePath).replace(/\.[^.]+$/, '.css');
// Return early, don't resolve this directory as a destination
if (statSync(file).isDirectory()) {
console.log('Recursing into subdir', file);
const newSource = path.relative(fullPath, file);
const newDest = path.resolve(destPath, newSource);
console.log(fullPath, newSource, newDest);
// Add each resolved source to paths
resolveSources(fullPath, newSource, newDest).forEach((x) => paths.add(x));
} else {
// Expect files here
const destFileName = relativeFile.replace(/\.[^.]+$/, '.css');
// Assuming dest is a directory
paths.add({ source: file, dest: path.resolve(base, dest, destFileName) });
console.log('resolved destination file: ', path.resolve(base, dest, destFileName));
}
});
}
return [...paths];
return { source: sourceFile, dest: destFile };
});
}
inputFiles.forEach((destitnationPath, sourcePath) => {
const destPath = [OUTPUT_PATH, destitnationPath].join('/');
inputFiles.forEach((options, sourcePath) => {
console.log('processing source', sourcePath);
const sources = resolveSources(ROOT_PATH.pathname, sourcePath, destPath);
const sources = resolveSources(ROOT_PATH, sourcePath, options);
console.log(`${sourcePath} resolved to:`, sources);
sources.forEach(({ source, dest }) => {
for (const { source, dest } of sources) {
console.log(`compiling source ${source} to ${dest}`);
const content = compile(source, defaultOptions);
console.log(content);
writeContentToFile(content, source, dest);
});
}
console.log('processed source', sourcePath);
});
Loading