Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] enable build with CSS variables #722

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion lib/builder/BuildContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,23 @@ const ProjectBuildContext = require("./ProjectBuildContext");
* @memberof module:@ui5/builder.builder
*/
class BuildContext {
constructor({rootProject}) {
constructor({rootProject, options = {}}) {
if (!rootProject) {
throw new Error(`Missing parameter 'rootProject'`);
}
this.rootProject = rootProject;
this.projectBuildContexts = [];
this.options = options;
}

getRootProject() {
return this.rootProject;
}

getOption(key) {
return this.options[key];
}

createProjectContext({project, resources}) {
const projectBuildContext = new ProjectBuildContext({
buildContext: this,
Expand Down
4 changes: 4 additions & 0 deletions lib/builder/ProjectBuildContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class ProjectBuildContext {
return this._project === this._buildContext.getRootProject();
}

getOption(key) {
return this._buildContext.getOption(key);
}

registerCleanupTask(callback) {
this.queues.cleanup.push(callback);
}
Expand Down
10 changes: 8 additions & 2 deletions lib/builder/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ module.exports = {
* @param {boolean} [parameters.dev=false]
* Decides whether a development build should be activated (skips non-essential and time-intensive tasks)
* @param {boolean} [parameters.selfContained=false] Flag to activate self contained build
* @param {boolean} [parameters.cssVariables=false] Flag to activate CSS variables generation
* @param {boolean} [parameters.jsdoc=false] Flag to activate JSDoc build
* @param {Array.<string>} [parameters.includedTasks=[]] List of tasks to be included
* @param {Array.<string>} [parameters.excludedTasks=[]] List of tasks to be excluded.
Expand All @@ -235,7 +236,7 @@ module.exports = {
async build({
tree, destPath, cleanDest = false,
buildDependencies = false, includedDependencies = [], excludedDependencies = [],
dev = false, selfContained = false, jsdoc = false,
dev = false, selfContained = false, cssVariables = false, jsdoc = false,
includedTasks = [], excludedTasks = [], devExcludeProject = []
}) {
const startTime = process.hrtime();
Expand All @@ -250,7 +251,12 @@ module.exports = {
virBasePath: "/"
});

const buildContext = new BuildContext({rootProject: tree});
const buildContext = new BuildContext({
rootProject: tree,
options: {
cssVariables: cssVariables
}
});
const cleanupSigHooks = registerCleanupSigHooks(buildContext);

const projects = {}; // Unique project index to prevent building the same project multiple times
Expand Down
12 changes: 12 additions & 0 deletions lib/tasks/TaskUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ class TaskUtil {
return this._projectBuildContext.isRootProject();
}

/**
* Retrieves a build option defined by it's <code>key</code.
* If no option with the given <code>key</code> is stored, <code>undefined</code> is returned.
*
* @param {string} key The option key
* @returns {object|undefined} The build option (or undefined)
* @public
*/
getBuildOption(key) {
return this._projectBuildContext.getOption(key);
}

/**
* Register a function that must be executed once the build is finished. This can be used to, for example,
* clean up files temporarily created on the file system. If the callback returns a Promise, it will be waited for.
Expand Down
3 changes: 2 additions & 1 deletion lib/types/library/LibraryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ class LibraryBuilder extends AbstractBuilder {
projectName: project.metadata.name,
librariesPattern: !taskUtil.isRootProject() ? "/resources/**/(*.library|library.js)" : undefined,
themesPattern: !taskUtil.isRootProject() ? "/resources/sap/ui/core/themes/*" : undefined,
inputPattern
inputPattern,
cssVariables: taskUtil.getBuildOption("cssVariables")
}
});
});
Expand Down
3 changes: 2 additions & 1 deletion lib/types/themeLibrary/ThemeLibraryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class ThemeLibraryBuilder extends AbstractBuilder {
projectName: project.metadata.name,
librariesPattern: !taskUtil.isRootProject() ? "/resources/**/(*.library|library.js)" : undefined,
themesPattern: !taskUtil.isRootProject() ? "/resources/sap/ui/core/themes/*" : undefined,
inputPattern: "/resources/**/themes/*/library.source.less"
inputPattern: "/resources/**/themes/*/library.source.less",
cssVariables: taskUtil.getBuildOption("cssVariables")
}
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.someClass {
color: @someColor
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:root{--someColor:#000}
/* Inline theming parameters */
#sap-ui-theme-theme\.j{background-image:url('data:text/plain;utf-8,%7B%22someColor%22%3A%22%23000%22%7D')}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@someColor: #000000;

:root {
--someColor: @someColor;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.someClass{color:#000}
/* Inline theming parameters */
#sap-ui-theme-theme\.j{background-image:url('data:text/plain;utf-8,%7B%22someColor%22%3A%22%23000%22%7D')}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"someColor":"#000"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.someClass{color:#000}
/* Inline theming parameters */
#sap-ui-theme-theme\.j{background-image:url('data:text/plain;utf-8,%7B%22someColor%22%3A%22%23000%22%7D')}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@someColor: black;
@import "Button.less";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.someClass{color:var(--someColor)}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.someClass{color:var(--someColor)}
19 changes: 19 additions & 0 deletions test/lib/builder/BuildContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ test("getRootProject", (t) => {
t.is(buildContext.getRootProject(), "pony", "Returned correct value");
});

test("getBuildOption", (t) => {
const buildContext = new BuildContext({
rootProject: "root_project",
options: {
a: true,
b: "Pony",
c: 235,
d: {
d1: "Bee"
}
}
});

t.is(buildContext.getOption("a"), true, "Returned 'boolean' value is correct");
t.is(buildContext.getOption("b"), "Pony", "Returned 'String' value is correct");
t.is(buildContext.getOption("c"), 235, "Returned 'Number' value is correct");
t.deepEqual(buildContext.getOption("d"), {d1: "Bee"}, "Returned 'object' value is correct");
});

test.serial("createProjectContext", (t) => {
class DummyProjectContext {
constructor({buildContext, project, resources}) {
Expand Down
12 changes: 12 additions & 0 deletions test/lib/builder/ProjectBuildContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ test("isRootProject: false", (t) => {
t.false(projectBuildContext.isRootProject(), "Correctly identified non-root project");
});

test("getBuildOption", (t) => {
const projectBuildContext = new ProjectBuildContext({
buildContext: {
getOption: () => "Pony"
},
project: "my project",
resources: "resources"
});

t.deepEqual(projectBuildContext.getOption("a"), "Pony", "Returned value is correct");
});

test("registerCleanupTask", (t) => {
const projectBuildContext = new ProjectBuildContext({
buildContext: {
Expand Down
65 changes: 65 additions & 0 deletions test/lib/builder/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const libraryØPath = path.join(__dirname, "..", "..", "fixtures", "library.ø")
const libraryCore = path.join(__dirname, "..", "..", "fixtures", "sap.ui.core-evo");
const libraryCoreBuildtime = path.join(__dirname, "..", "..", "fixtures", "sap.ui.core-buildtime");
const themeJPath = path.join(__dirname, "..", "..", "fixtures", "theme.j");
const themeLibraryEPath = path.join(__dirname, "..", "..", "fixtures", "theme.library.e");

const recursive = require("recursive-readdir");

Expand Down Expand Up @@ -111,9 +112,11 @@ test.serial("Build", async (t) => {
getTag: getTagStub
});
const isRootProjectStub = sinon.stub().returns(true);
const getOptionStub = sinon.stub().returns("Pony");
const dummyProjectContext = {
getResourceTagCollection: getResourceTagCollectionStub,
isRootProject: isRootProjectStub,
getOption: getOptionStub,
STANDARD_TAGS: {
OmitFromBuildResult: "👻"
}
Expand Down Expand Up @@ -888,6 +891,44 @@ test.serial("Build library.coreBuildtime: replaceBuildtime", (t) => {
});
});

test.serial("Build library with theme configured for CSS variables", (t) => {
const destPath = "./test/tmp/build/theme.j/dest-css-variables";
const expectedPath = "./test/expected/build/theme.j/dest-css-variables";
return builder.build({
tree: themeJTree,
cssVariables: true,
destPath
}).then(() => {
return findFiles(expectedPath);
}).then((expectedFiles) => {
// Check for all directories and files
assert.directoryDeepEqual(destPath, expectedPath);

return checkFileContentsIgnoreLineFeeds(t, expectedFiles, expectedPath, destPath);
}).then(() => {
t.pass();
});
});

test.serial("Build theme-library with CSS variables", (t) => {
const destPath = "./test/tmp/build/theme.library.e/dest-css-variables";
const expectedPath = "./test/expected/build/theme.library.e/dest-css-variables";
return builder.build({
tree: themeLibraryETree,
cssVariables: true,
destPath
}).then(() => {
return findFiles(expectedPath);
}).then((expectedFiles) => {
// Check for all directories and files
assert.directoryDeepEqual(destPath, expectedPath);

return checkFileContentsIgnoreLineFeeds(t, expectedFiles, expectedPath, destPath);
}).then(() => {
t.pass();
});
});

test.serial("Cleanup", async (t) => {
const BuildContext = require("../../../lib/builder/BuildContext");
const createProjectContextStub = sinon.spy(BuildContext.prototype, "createProjectContext");
Expand Down Expand Up @@ -1868,3 +1909,27 @@ const themeJTree = {
}
}
};

const themeLibraryETree = {
"id": "theme.library.e.id",
"version": "1.0.0",
"path": themeLibraryEPath,
"dependencies": [],
"_level": 0,
"_isRoot": true,
"specVersion": "1.1",
"type": "theme-library",
"metadata": {
"name": "theme.library.e",
"namespace": "theme/library/e",
"copyright": "Some fancy copyright"
},
"resources": {
"configuration": {
"paths": {
"src": "src",
"test": "test"
}
}
}
};
15 changes: 15 additions & 0 deletions test/lib/tasks/TaskUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ test("isRootProject", async (t) => {
t.is(res, true, "Correct result");
});

test("getBuildOption", (t) => {
const getOptionStub = sinon.stub().returns("Pony");
const taskUtil = new TaskUtil({
projectBuildContext: {
STANDARD_TAGS: ["some tag"],
getOption: getOptionStub
}
});

const res = taskUtil.getBuildOption("friend");

t.is(getOptionStub.callCount, 1, "ProjectBuildContext#getBuildOption got called once");
t.is(res, "Pony", "Correct result");
});

test("registerCleanupTask", async (t) => {
const registerCleanupTaskStub = sinon.stub();
const taskUtil = new TaskUtil({
Expand Down
6 changes: 6 additions & 0 deletions test/lib/types/themeLibrary/ThemeLibraryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ test("tasks", async (t) => {
taskUtil: {
isRootProject: () => {
return true;
},
getBuildOptions: () => {
return {};
},
getBuildOption: (key) => {
return key;
}
}
});
Expand Down