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
+ 85
71
Compare changes
  • Side-by-side
  • Inline
+ 85
71
import { compile } from 'sass'
import { SassString } from 'sass'
import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from 'fs'
import path from 'path'
import IS_EE from '../../config/helpers/is_ee_env.js'
import IS_JH from '../../config/helpers/is_jh_env.js'
const OUTPUT_PATH = 'app/assets/builds/'
import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from 'fs';
import path from 'path';
import { compile } from 'sass';
/* 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);
function resolveLoadPaths() {
let loadPaths = {
base: [
'app/assets/stylesheets'
],
const loadPaths = {
base: ['app/assets/stylesheets'],
vendor: [
// no-op files
'app/assets/stylesheets/_ee',
'app/assets/stylesheets/_jh',
// loaded last
'vendor/assets/stylesheets', // empty
'node_modules'
]
}
'node_modules',
],
};
if (IS_EE) {
loadPaths.base.unshift('ee/app/assets/stylesheets')
loadPaths.vendor.unshift('ee/app/assets/stylesheets/_ee')
loadPaths.base.unshift('ee/app/assets/stylesheets');
loadPaths.vendor.unshift('ee/app/assets/stylesheets/_ee');
}
if (IS_JH) {
loadPaths.base.unshift('jh/app/assets/stylesheets')
loadPaths.vendor.unshift('jh/app/assets/stylesheets/_jh')
loadPaths.base.unshift('jh/app/assets/stylesheets');
loadPaths.vendor.unshift('jh/app/assets/stylesheets/_jh');
}
return Object.values(loadPaths).flat()
.map((p) => path.resolve(ROOT_PATH.pathname, p))
return Object.values(loadPaths)
.flat()
.map((p) => path.resolve(ROOT_PATH.pathname, p));
}
const SASS_LOAD_PATHS = resolveLoadPaths();
const defaultOptions = {
loadPaths: SASS_LOAD_PATHS,
}
};
// Source => Destination (Relative to OUTPUT_PATH)
let inputFiles = new Map([
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'],
@@ -61,32 +61,41 @@ let inputFiles = new Map([
['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/_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/highlight/diff_custom_colors_deletion.scss', 'highlight/diff_custom_colors_deletion.css'],
[
'app/assets/stylesheets/highlight/diff_custom_colors_addition.scss',
'highlight/diff_custom_colors_addition.css',
],
[
'app/assets/stylesheets/highlight/diff_custom_colors_deletion.scss',
'highlight/diff_custom_colors_deletion.css',
],
['app/assets/stylesheets/highlight/themes/', 'highlight/themes/'],
])
]);
if (IS_EE) {
inputFiles.set('ee/app/assets/stylesheets/page_bundles/', 'page_bundles/')
inputFiles.set('ee/app/assets/stylesheets/page_bundles/', 'page_bundles/');
}
function writeContentToFile(content, src, dest) {
const destPath = path.resolve(ROOT_PATH.pathname, dest);
let outputFile;
if (!!src.relativePath) {
outputFile = path.resolve(destPath, src.relativePath)
if (src.relativePath) {
outputFile = path.resolve(destPath, src.relativePath);
console.log('Outputting to: ', outputFile, path.extname(outputFile));
if (path.extname(outputFile) == '.scss') {
if (path.extname(outputFile) === '.scss') {
outputFile = outputFile.replace(/\.[^.]+$/, '.css');
}
} else {
outputFile = destPath
outputFile = destPath;
}
console.log(`Writing ${src.fullPath} to ${outputFile}`)
console.log(`Writing ${src.fullPath} to ${outputFile}`);
if (!existsSync(path.dirname(outputFile))) {
mkdirSync(path.dirname(outputFile), { recursive: true });
}
@@ -94,14 +103,14 @@ function writeContentToFile(content, src, dest) {
}
function resolveSources(base, source, dest) {
console.log("Resolving source", source);
const destPath = path.resolve(base, dest)
console.log('Resolving source', source);
const destPath = path.resolve(base, dest);
const fullPath = path.resolve(base, source);
// 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: source, dest: destPath}]
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();
@@ -109,42 +118,47 @@ function resolveSources(base, source, dest) {
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
let file = path.resolve(fullPath, relativeFile);
console.log('resolved file: ', file)
// Return early, don't resolve this directory as a destination
if (statSync(file).isDirectory()) {
console.log("Recursing into subdir", file);
let newSource = path.relative(fullPath, file)
let 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))
}
})
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 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 [...paths];
}
inputFiles.forEach((dest, source, _) => {
const dest = [OUTPUT_PATH, dest].join('/');
console.log("processing source", source);
const sources = resolveSources(ROOT_PATH.pathname, source, dest);
console.log(`${source} resolved to:`, sources)
inputFiles.forEach((destitnationPath, sourcePath) => {
const destPath = [OUTPUT_PATH, destitnationPath].join('/');
console.log('processing source', sourcePath);
const sources = resolveSources(ROOT_PATH.pathname, sourcePath, destPath);
console.log(`${sourcePath} resolved to:`, sources);
sources.forEach(({ source, dest }) => {
console.log(`compiling source ${source} to ${dest}`)
const content = compile(source, defaultOptions)
writeContentToFile(content, source, dest)
console.log(`compiling source ${source} to ${dest}`);
const content = compile(source, defaultOptions);
writeContentToFile(content, source, dest);
});
console.log("processed source", source);
console.log('processed source', sourcePath);
});
Loading