Skip to content

chore(css): css preprocessors support enhancement #1492

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

Closed
wants to merge 1 commit 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
9 changes: 7 additions & 2 deletions addon/ng2/blueprints/ng2/files/__path__/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<meta charset="utf-8">
<title><%= jsComponentName %></title>
<base href="/">

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico"><% if (isMobile) { %>
<meta name="apple-mobile-web-app-capable" content="yes">
Expand All @@ -22,9 +21,15 @@
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon-180x180.png">
<link rel="apple-touch-startup-image" href="/icons/apple-touch-icon-180x180.png">
<% } %>

<% if (!arguments[0].files) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the purpose of this templating logic? Webpack entry points together with the HtmlWebpackPlugin should take care of inserting the css files here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe with our config and logic of injection styles we cannot use HtmlWebpackPlugin. Otherwise this line is used because template is going through the lodash _.template twice.. first when generating blueprint and then second when generating index.html for the dist/.

print (`<## _.forEach(files.css, css => { ##><link rel="stylesheet" type="text/css" href="<##- css ##>"><## }) ##>`);
} %>
</head>
<body>
<<%= prefix %>-root>Loading...</<%= prefix %>-root>

<% if (!arguments[0].files) {
print (`<## _.forEach(files.js, js => { ##><script src="<##- js ##>"></script><## }) ##>`);
} %>
</body>
</html>
3 changes: 3 additions & 0 deletions addon/ng2/blueprints/ng2/files/__path__/style.__styleext__
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body <% if (styleExt !== 'sass') { %>{<% } %>
background: #F9F9F9;
<% if (styleExt !== 'sass') { %>}<% } %>
5 changes: 4 additions & 1 deletion addon/ng2/blueprints/ng2/files/angular-cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
{
"main": "<%= sourceDir %>/main.ts",
"tsconfig": "<%= sourceDir %>/tsconfig.json",
"mobile": <%= isMobile %>
"mobile": <%= isMobile %>,
"styles": {
"src/style.<%= styleExt %>": { "output": "style.css", "autoImported": true }
}
}
],
"addons": [],
Expand Down
1 change: 1 addition & 0 deletions addon/ng2/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './webpack-build-production';
export * from './webpack-build-development';
export * from './webpack-build-mobile';
export * from './webpack-build-utils';
export * from './webpack-build-css';
11 changes: 5 additions & 6 deletions addon/ng2/models/webpack-build-common.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import * as path from 'path';
import * as CopyWebpackPlugin from 'copy-webpack-plugin';
import * as HtmlWebpackPlugin from 'html-webpack-plugin';
import * as webpack from 'webpack';
import { ForkCheckerPlugin } from 'awesome-typescript-loader';
import { CliConfig } from './config';

export function getWebpackCommonConfig(projectRoot: string, sourceDir: string) {
return {
name: 'main',
devtool: 'inline-source-map',
resolve: {
extensions: ['', '.ts', '.js'],
Expand Down Expand Up @@ -60,10 +60,6 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string) {
},
plugins: [
new ForkCheckerPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(projectRoot, `./${sourceDir}/index.html`),
chunksSortMode: 'dependency'
}),
new webpack.optimize.CommonsChunkPlugin({
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have a custom plugin for that which injects .css files configured with autoImported: true into index.html. In this plugin we have also configuration for mobile support which generates content automactically (app-shell).

name: ['polyfills']
}),
Expand All @@ -73,7 +69,10 @@ export function getWebpackCommonConfig(projectRoot: string, sourceDir: string) {
filename: 'inline.js',
sourceMapFilename: 'inline.map'
}),
new CopyWebpackPlugin([{from: path.resolve(projectRoot, './public'), to: path.resolve(projectRoot, './dist')}])
new CopyWebpackPlugin([{
from: path.resolve(projectRoot, './public'),
to: path.resolve(projectRoot, './dist')
}])
Copy link

Choose a reason for hiding this comment

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

@jkuri public directory should be copied as is, in full. styles should be part of src

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks, reverted.

],
node: {
global: 'window',
Expand Down
41 changes: 41 additions & 0 deletions addon/ng2/models/webpack-build-css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as path from 'path';
import * as ExtractTextPlugin from 'extract-text-webpack-plugin';
import * as existsSync from 'exists-sync';
import { CliConfig } from './config';

export function getWebpackCSSConfig(projectRoot: string, sourceDir: string) {
const styles = CliConfig.fromProject().apps.map(app => app.styles);
let entries = {};

styles.forEach(style => {
for (let src in style) {
if (existsSync(path.resolve(projectRoot, src))) {
entries[style[src].output] = path.resolve(projectRoot, `./${src}`);
}
}
});

return {
name: 'styles',
resolve: {
root: path.resolve(projectRoot)
},
context: path.resolve(__dirname),
entry: entries,
output: {
path: path.resolve(projectRoot, './dist'),
filename: '[name]'
},
module: {
loaders: [
{ test: /\.css$/i, loader: ExtractTextPlugin.extract(['css-loader']) },
{ test: /\.sass$|\.scss$/i, loader: ExtractTextPlugin.extract(['css-loader', 'sass-loader']) },
{ test: /\.less$/i, loader: ExtractTextPlugin.extract(['css-loader', 'less-loader']) },
{ test: /\.styl$/i, loader: ExtractTextPlugin.extract(['css-loader', 'stylus-loader']) }
]
},
plugins: [
new ExtractTextPlugin('[name]')
]
}
};
8 changes: 1 addition & 7 deletions addon/ng2/models/webpack-build-mobile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as webpack from 'webpack';
import * as path from 'path';
import * as OfflinePlugin from 'offline-plugin';
import * as CopyWebpackPlugin from 'copy-webpack-plugin';
import { PrerenderWebpackPlugin } from '../utilities/prerender-webpack-plugin.ts';
import { CliConfig } from './config';
Copy link
Contributor

Choose a reason for hiding this comment

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

This is core mobile functionality, it shouldn't be removed.

Copy link
Contributor Author

@jkuri jkuri Aug 3, 2016

Choose a reason for hiding this comment

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

I merged that functionallity in our "html" plugin.


export const getWebpackMobileConfigPartial = function (projectRoot: string, sourceDir: string) {
Expand All @@ -11,12 +10,7 @@ export const getWebpackMobileConfigPartial = function (projectRoot: string, sour
new CopyWebpackPlugin([
{from: path.resolve(projectRoot, `./${sourceDir}/icons`), to: path.resolve(projectRoot, './dist/icons')},
{from: path.resolve(projectRoot, `./${sourceDir}/manifest.webapp`), to: path.resolve(projectRoot, './dist')}
]),
new PrerenderWebpackPlugin({
templatePath: 'index.html',
configPath: path.resolve(projectRoot, `./${sourceDir}/main-app-shell.ts`),
appPath: path.resolve(projectRoot, `./${sourceDir}`)
})
])
]
}
};
Expand Down
25 changes: 22 additions & 3 deletions addon/ng2/models/webpack-config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as path from 'path';
import * as fs from 'fs';
import * as webpackMerge from 'webpack-merge';
import * as AssetsPlugin from 'assets-webpack-plugin';
import { HtmlCliPlugin } from '../utilities/html-cli-plugin';
import { CliConfig } from './config';
import { NgCliEnvironmentPlugin } from '../utilities/environment-plugin';
import {
Expand All @@ -9,6 +11,7 @@ import {
getWebpackProdConfigPartial,
getWebpackMobileConfigPartial,
getWebpackMobileProdConfigPartial
getWebpackCSSConfig
} from './';

export class NgCliWebpackConfig {
Expand All @@ -22,6 +25,7 @@ export class NgCliWebpackConfig {
private webpackMaterialE2EConfig: any;
private webpackMobileConfigPartial: any;
private webpackMobileProdConfigPartial: any;
private webpackCSSConfig: any;

constructor(public ngCliProject: any, public target: string, public environment: string) {
const sourceDir = CliConfig.fromProject().defaults.sourceDir;
Expand All @@ -31,6 +35,7 @@ export class NgCliWebpackConfig {
this.webpackBaseConfig = getWebpackCommonConfig(this.ngCliProject.root, sourceDir);
this.webpackDevConfigPartial = getWebpackDevConfigPartial(this.ngCliProject.root, sourceDir);
this.webpackProdConfigPartial = getWebpackProdConfigPartial(this.ngCliProject.root, sourceDir);
this.webpackCSSConfig = getWebpackCSSConfig(this.ngCliProject.root, sourceDir);

if (CliConfig.fromProject().apps[0].mobile){
this.webpackMobileConfigPartial = getWebpackMobileConfigPartial(this.ngCliProject.root, sourceDir);
Expand All @@ -40,20 +45,34 @@ export class NgCliWebpackConfig {
}

this.generateConfig();
this.config.plugins.unshift(new NgCliEnvironmentPlugin({
this.config[0].plugins.unshift(new NgCliEnvironmentPlugin({
path: path.resolve(this.ngCliProject.root, `./${sourceDir}/app/environments/`),
src: 'environment.ts',
dest: `environment.${this.environment}.ts`
}));

const assetsPluginInstance = new AssetsPlugin({ filename: 'cli.assets.json' });
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the purpose of this cli.assets.json file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It temporarily stores all the assets in a file so I know which files needs to be included.
Please see https://webpack.github.io/docs/long-term-caching.html

const htmlCliPlugin = new HtmlCliPlugin();

this.config.forEach(conf => {
conf.plugins.unshift(assetsPluginInstance);
conf.plugins.unshift(htmlCliPlugin);
});
}

generateConfig(): void {
switch (this.target) {
case "development":
this.config = webpackMerge(this.webpackBaseConfig, this.webpackDevConfigPartial);
this.config = [
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought we talked about not having multiple configs. What changed?

webpackMerge(this.webpackBaseConfig, this.webpackDevConfigPartial),
this.webpackCSSConfig
];
break;
case "production":
this.config = webpackMerge(this.webpackBaseConfig, this.webpackProdConfigPartial);
this.config = [
webpackMerge(this.webpackBaseConfig, this.webpackProdConfigPartial),
this.webpackCSSConfig
];
break;
default:
throw new Error("Invalid build target. Only 'development' and 'production' are available.");
Expand Down
2 changes: 1 addition & 1 deletion addon/ng2/tasks/serve-webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = Task.extend({
var config: NgCliWebpackConfig = new NgCliWebpackConfig(this.project, commandOptions.target, commandOptions.environment).config;
// This allows for live reload of page when changes are made to repo.
// https://webpack.github.io/docs/webpack-dev-server.html#inline-mode
config.entry.main.unshift(`webpack-dev-server/client?http://${commandOptions.host}:${commandOptions.port}/`);
config[0].entry.main.unshift(`webpack-dev-server/client?http://${commandOptions.host}:${commandOptions.port}/`);
webpackCompiler = webpack(config);

webpackCompiler.apply(new ProgressPlugin({
Expand Down
70 changes: 70 additions & 0 deletions addon/ng2/utilities/html-cli-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as fs from 'fs';
import * as path from 'path';
import * as _ from 'lodash';
import * as MemoryFS from 'memory-fs';
import { CliConfig } from '../models/config';

export class HtmlCliPlugin {
private cachedTemplate: string;

apply(compiler) {
if (compiler.options.name === 'main' && CliConfig.fromProject().apps[0].mobile) {
compiler.plugin('emit', this.cacheTemplate);
}
compiler.plugin('done', this.generateIndexHtml);
}

cacheTemplate(c, callback) {
const sourceDir = CliConfig.fromProject().defaults.sourceDir;
const projectRoot = path.resolve(sourceDir, '..');
const appShellPath = path.resolve(projectRoot, `./${sourceDir}/main-app-shell.ts`);
const appShell = require(appShellPath);
const bootloader = appShell.getBootloader();
const indexHtml = path.resolve(sourceDir, 'index.html');
const assetsPath = path.resolve(projectRoot, 'cli.assets.json');

appShell.serialize(bootloader, fs.readFileSync(indexHtml, 'utf8')).then(html => {
console.log(html)
this.cachedTemplate = html;
callback();
});
}

generateIndexHtml(stats) {
const isMobile = CliConfig.fromProject().apps[0].mobile;
const sourceDir = CliConfig.fromProject().defaults.sourceDir;
const projectRoot = path.resolve(sourceDir, '..');
const assetsPath = path.resolve(projectRoot, 'cli.assets.json');
const contents = JSON.parse(fs.readFileSync(assetsPath, 'utf8'));
const indexHtml = path.resolve(sourceDir, 'index.html');
let tpl;
let mfs;
let files = { js: [], css: [] };

Object.keys(contents).forEach(key => {
let type = Object.keys(contents[key])[0];
files[type].unshift(contents[key][type]);
});

if (this.cachedTemplate) {
tpl = this.cachedTemplate;
tpl = _.template(tpl.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/##/g, '%'));
writeTemplate(stats, tpl, files);
} else {
tpl = _.template(fs.readFileSync(indexHtml, 'utf8').replace(/##/g, '%'));
writeTemplate(stats, tpl, files);
}

function writeTemplate(stats, tpl, files) {
const destHtml = path.resolve(stats.compilation.compiler.outputPath, 'index.html');

if (stats.compilation.compiler.outputFileSystem instanceof MemoryFS) {
if (!mfs) { mfs = stats.compilation.compiler.outputFileSystem; }
mfs.writeFileSync(destHtml, tpl({ files: files }), 'utf8');
} else {
fs.writeFileSync(destHtml, tpl({ files: files }), 'utf8');
}
}
}

}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@types/rimraf": "0.0.25-alpha",
"@types/webpack": "^1.12.22-alpha",
"angular2-template-loader": "^0.4.0",
"assets-webpack-plugin": "^3.4.0",
"awesome-typescript-loader": "^2.1.1",
"chalk": "^1.1.3",
"compression-webpack-plugin": "^0.3.1",
Expand All @@ -48,11 +49,11 @@
"exit": "^0.1.2",
"exports-loader": "^0.6.3",
"expose-loader": "^0.7.1",
"extract-text-webpack-plugin": "^2.0.0-beta.3",
"file-loader": "^0.8.5",
"fs-extra": "^0.30.0",
"glob": "^7.0.3",
"handlebars": "^4.0.5",
"html-webpack-plugin": "^2.19.0",
"istanbul-instrumenter-loader": "^0.2.0",
"json-loader": "^0.5.4",
"karma-sourcemap-loader": "^0.3.7",
Expand All @@ -74,7 +75,7 @@
"remap-istanbul": "^0.6.4",
"resolve": "^1.1.7",
"rimraf": "^2.5.3",
"sass-loader": "^3.2.0",
"sass-loader": "^3.2.3",
"shelljs": "^0.7.0",
"silent-error": "^1.0.0",
"source-map-loader": "^0.1.5",
Expand Down