Skip to content

feat(sass): Added Support for Less to Sass Conversion #692

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 1 commit into from
Dec 15, 2017
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
168 changes: 166 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ module.exports = function (grunt) {

function init () {

// '--sass' command line argument exists?
var sassBuild = grunt.option('sass');

grunt.initConfig({
availabletasks: {
tasks: {
Expand Down Expand Up @@ -94,6 +97,23 @@ module.exports = function (grunt) {
dest: 'dist/less/dependencies/patternfly',
expand: true,
flatten: true
},
distsass: {
src: ['styles/_angular-patternfly.scss'],
dest: 'dist/sass',
expand: true,
flatten: true
},
sassBuild:{
files: [
{
// copy css built from sass into dist/styles
expand: true,
cwd: 'dist/sass',
src: ['**/*.css', '**/*.map'],
dest: 'dist/styles/'
}
]
}
},
'string-replace': {
Expand All @@ -115,6 +135,128 @@ module.exports = function (grunt) {
}
}
},
lessToSass: {
convert_within_custom_replacements: {
files: [
{
expand: true,
cwd: 'styles',
src: ['**/*.less', '!angular-patternfly.less'],
dest: 'dist/sass/',
rename: function(dest, src) {
return dest + '_' + src.replace('.less', '.scss');
}
},
{
expand: true,
cwd: 'src',
src: ['**/*.less'],
dest: 'dist/sass/',
rename: function(dest, src) {
return dest + '_' + src.split('/').pop().replace('.less', '.scss');
}
}
],
options: {
excludes: ['variables', 'default'],
replacements: [
{
// Customize variable conversion to include newer css reserved words.
pattern: /(?!@debug|@import|@media|@keyframes|@font-face|@include|@extend|@mixin|@supports|@-\w)@/gi,
replacement: '$',
order: 0
},
{
// Add !default flag to variable declarations without leading whitespace.
pattern: /^(\$.*?:.*?);(\s*\/\/.*)?$/mgi,
replacement: '$1 !default;$2',
order: 2
},
{
// Include mixins with no arguments
pattern: /(\s+)\.([\w\-]+)\(\)/gi,
replacement: '$1@include $2()',
order: 3
},
{
// Interpolates second ampersand where double ampersands are used
pattern: /\&\&/gi,
replacement: '&#{&}',
order: 20
},
{
// Interpolates ampersands that directly follow (are touching) a definition
// e.g. somedef& becomes somedef#{&}
pattern: /(\w+)\&/gi,
replacement: '$1#{&}',
order: 30
},
{
// Namespaced mixins are detected as includes by default conversion
// process. Remove namespacing by concatenating namespace and mixin name.
// #gradient {
// @include striped(){...}
// }
//
// becomes
//
// @mixin gradient-striped(){...}
pattern: /^#([\w\-]+)\s*{\s*@include\s*([\w\-]*)\((.*)\)\s*{([\s\S]*?)}\s*}/mgi,
replacement: '@mixin $1-$2($3){$4}',
order: 40
},
// Fix invocation of namespaced mixins. Replace #namespace > .mixin()
// or #namespace.mixin() with @include namespace-mixin()
{
pattern: /#(\w*)\s*\>?\s*\.(\w*)(\(.*\))/gi,
replacement: '@include $1-$2$3',
order: 50
},
{
// Remove "!default" flag from mixin declarations
pattern: /@mixin.*!default.*/gi,
replacement: function(match) {
return match.replace(/\s*!default\s*/gi, '');
},
order: 60
},
{
// Replace semi-colons with commas in mixins and includes
pattern: /(@mixin |@include )([\w\-]*)\s*(\(.*\))(\s*[{;]?)/gi,
replacement: function(match, p1, p2, p3, p4) {
return p1 + p2 + p3.replace(/;/g, ',') + p4;
},
order: 70
},
{
// Fix bug in grunt-less-to-sass that puts "!important" inside mixin and css function parens.
pattern: /^(\s*[\w\-]*:\s*[\w\-]*)\((.*?)\s*!important.*\)(.*);(.*)$/mgi,
replacement: '$1($2) !important$3;$4',
order: 80
},
{
pattern: /\&:extend\((.*)\)/gi,
replacement: '@extend $1',
order: 90
},
]
}
}
},
sass: {
patternfly: {
files: {
'dist/sass/angular-patternfly.css': ['styles/build.scss']
},
options: {
outputStyle: 'expanded',
includePaths: [
'dist/sass',
'node_modules/patternfly/dist/sass'
]
}
}
},
less: {
patternfly: {
files: {
Expand Down Expand Up @@ -355,7 +497,13 @@ module.exports = function (grunt) {
}
});

grunt.registerTask('copymain', ['copy:docdata', 'copy:fa', 'copy:img', 'copy:distimg', 'copy:distless', 'copy:distlessDependencies']);
grunt.registerTask('shipcss', function() {
if (sassBuild) {
grunt.task.run('copy:sassBuild');
}
});

grunt.registerTask('copymain', ['copy:docdata', 'copy:fa', 'copy:img', 'copy:distimg', 'copy:distless', 'copy:distlessDependencies', 'copy:distsass']);

// You can specify which modules to build as arguments of the build task.
grunt.registerTask('build', 'Create bootstrap build files', function () {
Expand All @@ -375,7 +523,23 @@ module.exports = function (grunt) {
concatSrc = 'src/**/*.js';
}

grunt.task.run(['clean', 'lint', 'test', 'ngtemplates', 'concat', 'ngAnnotate', 'uglify:build', 'less', 'cssmin', 'copymain', 'string-replace', 'ngdocs', 'clean:templates']);
grunt.task.run([
'clean',
'lint',
'test',
'ngtemplates',
'concat',
'ngAnnotate',
'uglify:build',
'less',
'lessToSass',
'sass',
'shipcss',
'cssmin',
'copymain',
'string-replace',
'ngdocs',
'clean:templates']);
});

// Runs all the tasks of build with the exception of tests
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,22 @@ Note:
</style>
```

#### Less to Sass Conversion

During the build process Less files are converted to Sass files in `/dist/sass`. Then the Sass files are compiled into `/dist/sass/angular-patternfly.css`. If you would like to copy the Sass generated css into the main `/dist/styles` directory, execute:

```
grunt build --sass
```

This task will copy `/dist/sass/angular-patternfly.css` to `/dist/styles/angular-patternfly.css`. Then the build process will minimize the css in `/dist/styles`.

The Less to Sass Conversion step will be accomplished and managed as a part of any Pull Request which includes Less file changes. Although contributors may want to build and test their style changes with Sass before submitting a Pull Request, this step should always be tested and validated by reviewers before a style change is merged and released. If a contributor is having issues with Sass conversion that they cannot resolve, Pull Request reviewers will need to ensure that the Sass conversion step is successfully accomplished, tested, and included in the Pull Request before it is approved and merged.

For more detailed information, please read [PatternFly Less to Sass Conversion](https://github.com/patternfly/patternfly#less-to-sass-conversion)

*Note:* When a Less file is added/deleted/renamed it needs to be updated in the main Less import file `/styles/angular-patternfly.less` and the main Sass import file `styles/_angular-patternfly.scss`.

### Using with Webpack

In order to use Angular-Patternfly in a Webpack-bundled application there are some things you need to keep in mind:
Expand Down
2 changes: 1 addition & 1 deletion eslint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ globals:
rules:
strict: [2, "function"]
quotes: 0
camelcase: 2
camelcase: 1
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason for this change?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, was throwing an error due to new task in gruntfile 'convert_within_custom_replacements' not being camelcase:

lessToSass: {
        convert_within_custom_replacements: 

indent: [2, 2]
new-cap:
- 2
Expand Down
Loading