-
Notifications
You must be signed in to change notification settings - Fork 12k
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
body <% if (styleExt !== 'sass') { %>{<% } %> | ||
background: #F9F9F9; | ||
<% if (styleExt !== 'sass') { %>}<% } %> |
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'], | ||
|
@@ -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({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this removed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have a custom plugin for that which injects |
||
name: ['polyfills'] | ||
}), | ||
|
@@ -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') | ||
}]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks, reverted. |
||
], | ||
node: { | ||
global: 'window', | ||
|
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]') | ||
] | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is core mobile functionality, it shouldn't be removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
@@ -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}`) | ||
}) | ||
]) | ||
] | ||
} | ||
}; | ||
|
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 { | ||
|
@@ -9,6 +11,7 @@ import { | |
getWebpackProdConfigPartial, | ||
getWebpackMobileConfigPartial, | ||
getWebpackMobileProdConfigPartial | ||
getWebpackCSSConfig | ||
} from './'; | ||
|
||
export class NgCliWebpackConfig { | ||
|
@@ -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; | ||
|
@@ -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); | ||
|
@@ -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' }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of this There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
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 = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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."); | ||
|
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(/</g, '<').replace(/>/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'); | ||
} | ||
} | ||
} | ||
|
||
} |
There was a problem hiding this comment.
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.There was a problem hiding this comment.
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 generatingindex.html
for thedist/
.