Skip to content

build: Angular2App is now a class, and accepts a set of options for SCSS #412

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

Merged
merged 2 commits into from
Apr 9, 2016
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ We support all major CSS preprocessors:

To use one just install for example `npm install node-sass` and rename `.css` files in your project to `.scss` or `.sass`. They will be compiled automatically.

The `Angular2App`'s options argument has `sassCompiler`, `lessCompiler`, `stylusCompiler` and `compassCompiler` options that are passed directly to their respective CSS preprocessors.

## Known issues

Expand Down
69 changes: 69 additions & 0 deletions docs/design/ngConfig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# ngConfig - Design

## Goals

Currently, a project scaffolded with the CLI have no way of specifying options and configurations affecting their projects. There are ways to affect the build (with the `angular-cli-build.js` file), but the following questions cannot be answered without actual project options:

* Where in my directory is my karma.conf file?
* What is my firebase database URL?
* Where is my client code?
* How can I use a different
* Any other backend I want to run prior to `ng serve`?

# Proposed Solution

Since the data is static, we only need to keep it in a static store somewhere.

One solution would be to keep the data in the `package.json`. Unfortunately, the metadata contains too much data and the `package.json` file would become unmanageable.

Instead of polluting the package file, a `angular-cli.json` file will be created that contains all the values. Access to that file will be allowed to the user if he knows the structure of the file (unknown keys will be kept but ignored), and it's easy to read and write. We can also keep the file formatted.


## Fallback

There should be two `angular-cli.json` files; one for the project and a general one. The general one should contain information that can be useful when scaffolding new apps, or informations about the user.

The project `angular-cli.json` goes into the project root. The global configuration should live in the `$HOME` directory of the user.

## Structure

The structure should be defined by a JSON schema (see [here](http://json-schema.org/)). The schema will be used to generate the `d.ts`, but that file will be kept in the file system along the schema for IDEs.

Every PR that would change the schema should include the update to the `d.ts`.

# API

## CLI

#### Getting values

The new command `get` should be used to output values on the terminal. It takes a set of flags and an optional array of [paths](#path);

* `--glob` or `-g`; the path follows a glob format, where `*` can be replaced by any amount of characters and `?` by a single character. This will output `name=value` for each values matched.

Otherwise, outputs the value of the path passed in. If multiple paths are passed in, they follow the format of `name=value`.

#### Setting values

The new command `set` should be used to set values in the local configuration file. It takes a set of flags and an optional array of `[path](#path)=value`;

* `--global`; sets the value in the global configuration.
* `--remove`; removes the key (no value should be passed in).

The schema needs to be taken into account when setting the value of the field;

* If the field is a number, the string received from the command line is parsed. `NaN` throws an error.
* If the field is an object, an error is thrown.
* If the path is inside an object but the object hasn't been defined yet, sets the object with empty values (use the schema to create a valid object).

#### Path<a name="path"></a>

The paths are json formatted path; each `.` separates a map, while `[]` indicates an index in an array.

An example is the following:

keyA.keyB.arrayC[3].value=123

## Model

A model should be created that will include loading and saving the configuration, including the global configuration.
12 changes: 6 additions & 6 deletions lib/broccoli/angular-broccoli-compass.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ class CompassPlugin extends Plugin {
}

compile(fileName, inputPath, outputPath) {
let sassOptions = {
file: path.normalize(fileName),
includePaths: this.inputPaths,
let sassOptions = Object.assign(this.options, {
data: '@import "compass"; .transition { @include transition(all); }',
file: fileName,
includePaths: [inputPath].concat(this.options.inputPaths || []),
importer: compass
};
});

let result = sass.renderSync(sassOptions);
let filePath = fileName.replace(inputPath, outputPath).replace(/\.s[ac]ss$/, '.css');
Expand All @@ -47,13 +47,13 @@ class CompassPlugin extends Plugin {
}
}

exports.makeBroccoliTree = (sourceDir) => {
exports.makeBroccoliTree = (sourceDir, options) => {
if (sass && compass) {
let compassSrcTree = new Funnel(sourceDir, {
include: ['**/*.scss', '**/*.sass'],
allowEmpty: true
});

return new CompassPlugin([compassSrcTree]);
return new CompassPlugin([compassSrcTree], options);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then here exactly as you did for sass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

6 changes: 3 additions & 3 deletions lib/broccoli/angular-broccoli-less.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,21 @@ class LESSPlugin extends Plugin {
compile(fileName, inputPath, outputPath) {
let content = fs.readFileSync(fileName, 'utf8');

return less.render(content)
return less.render(content, this.options)
.then(output => {
let filePath = fileName.replace(inputPath, outputPath).replace(/\.less$/, '.css');
fse.outputFileSync(filePath, output.css, 'utf8');
});
}
}

exports.makeBroccoliTree = (sourceDir) => {
exports.makeBroccoliTree = (sourceDir, options) => {
if (less) {
let lessSrcTree = new Funnel(sourceDir, {
include: ['**/*.less'],
allowEmpty: true
});

return new LESSPlugin([lessSrcTree]);
return new LESSPlugin([lessSrcTree], options);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also add additional options same as you did for sass. And then call it;
less.render(content, this.options).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

29 changes: 17 additions & 12 deletions lib/broccoli/angular-broccoli-sass.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
const requireOrNull = require('./require-or-null');
const Plugin = require('broccoli-caching-writer');
const fse = require('fs-extra');
const path = require('path');
const Funnel = require('broccoli-funnel');

let sass = requireOrNull('node-sass');
Expand All @@ -24,26 +23,32 @@ class SASSPlugin extends Plugin {
}

build() {
this.listEntries().forEach(e => {
let fileName = path.resolve(e.basePath, e.relativePath);
this.listFiles().forEach(fileName => {
this.compile(fileName, this.inputPaths[0], this.outputPath);
});
}

compile(fileName, inputPath, outputPath) {
let sassOptions = {
file: path.normalize(fileName),
includePaths: this.inputPaths
};
const outSourceName = fileName.replace(inputPath, outputPath);
const outFileName = outSourceName.replace(/\.s[ac]ss$/, '.css');

let result = sass.renderSync(sassOptions);
let filePath = fileName.replace(inputPath, outputPath).replace(/\.s[ac]ss$/, '.css');
// We overwrite file, outFile and include the file path for the includePath.
// We also make sure the options don't include a data field.
const sassOptions = Object.assign(this.options, {
data: null,
file: fileName,
outFile: outFileName,
includePaths: [inputPath].concat(this.options.includePaths || [])
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could do here:

let sassOptions = {
  file: fileName,
  outFile: outFileName,
  includePaths: [inputPath].concat(this.options.additionalPaths || [])
};

sassOptions = Object.assign(sassOptions, this.options);

since there are many other options that can be set (examples).

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, but removed additionalPaths and copySources.

fse.outputFileSync(filePath, result.css, 'utf8');
const result = sass.renderSync(sassOptions);
fse.outputFileSync(outFileName, result.css, 'utf-8');
}
}

exports.makeBroccoliTree = (sourceDir) => {
exports.makeBroccoliTree = (sourceDir, options) => {
options = options || {};

// include sass support only if compass-importer is not installed
let compass = requireOrNull('compass-importer');
if (!compass) {
Expand All @@ -56,6 +61,6 @@ exports.makeBroccoliTree = (sourceDir) => {
allowEmpty: true
});

return new SASSPlugin([sassSrcTree]);
return new SASSPlugin([sassSrcTree], options);
}
};
10 changes: 7 additions & 3 deletions lib/broccoli/angular-broccoli-stylus.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,24 @@ class StylusPlugin extends Plugin {
compile(fileName, inputPath, outputPath) {
let content = fs.readFileSync(fileName, 'utf8');

return stylus.render(content, { filename: path.basename(fileName) }, function(err, css) {
const options = Object.assign(this.options, {
filename: path.basename(fileName)
});

return stylus.render(content, options, function(err, css) {
let filePath = fileName.replace(inputPath, outputPath).replace(/\.styl$/, '.css');
fse.outputFileSync(filePath, css, 'utf8');
});
}
}

exports.makeBroccoliTree = (sourceDir) => {
exports.makeBroccoliTree = (sourceDir, options) => {
if (stylus) {
let stylusSrcTree = new Funnel(sourceDir, {
include: ['**/*.styl'],
allowEmpty: true
});

return new StylusPlugin([stylusSrcTree]);
return new StylusPlugin([stylusSrcTree], options);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as less and then call stylus.render(content, this.options, function(err, css) { ..
Please be careful here, this.options should have filename defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup

Loading