Skip to content

chore(docs): add global lib docs #1747

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
Aug 22, 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
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ The generated project has dependencies that require **Node 4 or greater**.
* [Global styles](#global-styles)
* [CSS preprocessor integration](#css-preprocessor-integration)
* [3rd Party Library Installation](#3rd-party-library-installation)
* [Global Library Installation](#global-library-installation)
* [Updating angular-cli](#updating-angular-cli)
* [Known Issues](#known-issues)
* [Development Hints for hacking on angular-cli](#development-hints-for-hacking-on-angular-cli)
Expand Down Expand Up @@ -250,6 +251,8 @@ The `styles.css` file allows users to add global styles and supports
If the project is created with the `--style=sass` option, this will be a `.sass`
file instead, and the same applies to `scss/less/styl`.

You can add more global styles via the `apps[0].styles` property in `angular-cli.json`.

### CSS Preprocessor integration

Angular-CLI supports all major CSS preprocessors:
Expand Down Expand Up @@ -295,6 +298,42 @@ npm install moment --save
npm install @types/moment --save-dev
```

### Global Library Installation

Some javascript libraries need to be added to the global scope, and loaded as if
they were in a script tag. We can do this using the `apps[0].scripts` and
`apps[0].styles` properties of `angular-cli.json`.

As an example, to use [Boostrap 4](http://v4-alpha.getbootstrap.com/) this is
what you need to do:

First install Bootstrap from `npm`:

```bash
npm install bootstrap@next
```

Then add the needed script files to to `apps[0].scripts`.

```
"scripts": [
"../node_modules/jquery/dist/jquery.js",
"../node_modules/tether/dist/js/tether.js",
"../node_modules/bootstrap/dist/js/bootstrap.js"
],
```

Finally add the Bootstrap CSS to the `apps[0].styles` array:
```
"styles": [
"styles.css",
"../node_modules/bootstrap/dist/css/bootstrap.css"
],
```

Restart `ng serve` if you're running it, and Bootstrap 4 should be working on
your app.

### Updating angular-cli

To update `angular-cli` to a new version, you must update both the global package and your project's local package.
Expand Down
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 @@ -14,7 +14,10 @@
"tsconfig": "tsconfig.json",
"prefix": "<%= prefix %>",
"mobile": <%= isMobile %>,
"styles": "styles.<%= styleExt %>",
"styles": [
"styles.<%= styleExt %>"
],
"scripts": [],
"environments": {
"source": "environments/environment.ts",
"prod": "environments/environment.prod.ts",
Expand Down
22 changes: 18 additions & 4 deletions addon/ng2/models/webpack-build-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,26 @@ export function getWebpackCommonConfig(projectRoot: string, environment: string,

const appRoot = path.resolve(projectRoot, appConfig.root);
const appMain = path.resolve(appRoot, appConfig.main);
const styles = path.resolve(appRoot, appConfig.styles);
const styles = appConfig.styles.map(style => path.resolve(appRoot, style));
const scripts = appConfig.scripts.map(script => path.resolve(appRoot, script));
const lazyModules = findLazyModules(appRoot);

let entry = {
main: [appMain]
};

// Only add styles/scripts if there's actually entries there
if (appConfig.styles.length > 0) entry.styles = styles;
if (appConfig.scripts.length > 0) entry.scripts = scripts;

return {
devtool: 'source-map',
resolve: {
extensions: ['', '.ts', '.js'],
root: appRoot
},
context: path.resolve(__dirname, './'),
entry: {
main: [appMain, styles]
},
entry: entry,
output: {
path: path.resolve(projectRoot, appConfig.outDir),
filename: '[name].bundle.js'
Expand Down Expand Up @@ -66,6 +73,9 @@ export function getWebpackCommonConfig(projectRoot: string, environment: string,
       { include: styles, test: /\.less$/, loaders: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'] },
       { include: styles, test: /\.scss$|\.sass$/, loaders: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'] },

// load global scripts using script-loader
{ include: scripts, test: /\.js$/, loader: 'script-loader' },

       { test: /\.json$/, loader: 'json-loader' },
       { test: /\.(jpg|png)$/, loader: 'url-loader?limit=10000' },
       { test: /\.html$/, loader: 'raw-loader' },
Expand All @@ -90,6 +100,10 @@ export function getWebpackCommonConfig(projectRoot: string, environment: string,
.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")),
path.resolve(appRoot, appConfig.environments[environment])
),
new webpack.optimize.CommonsChunkPlugin({
// Optimizing ensures loading order in index.html
name: ['styles', 'scripts', 'main'].reverse();
}),
new webpack.optimize.CommonsChunkPlugin({
minChunks: Infinity,
name: 'inline',
Expand Down
30 changes: 11 additions & 19 deletions lib/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,27 +49,19 @@
"mobile": {
"type": "boolean"
},
"additionalEntries": {
"description": "Additional files to be included in the build.",
"styles": {
"description": "Global styles to be included in the build.",
"type": "array",
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"input": {
"type": "string"
},
"output": {
"type": "string"
}
},
"additionalProperties": false
}
]
"type": "string"
},
"additionalProperties": false
},
"scripts": {
"description": "Global scripts to be included in the build.",
"type": "array",
"items": {
"type": "string"
},
"additionalProperties": false
},
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"rimraf": "^2.5.3",
"rxjs": "^5.0.0-beta.11",
"sass-loader": "^3.2.0",
"script-loader": "^0.7.0",
"shelljs": "^0.7.0",
"silent-error": "^1.0.0",
"source-map-loader": "^0.1.5",
Expand Down
64 changes: 55 additions & 9 deletions tests/e2e/e2e_workflow.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ describe('Basic end-to-end Workflow', function () {
expect(indexHtml).to.include('main.bundle.js');
});

it('styles.css is added to main bundle', function() {
it('styles.css is added to styles bundle', function() {
this.timeout(420000);

let stylesPath = path.join(process.cwd(), 'src', 'styles.css');
Expand All @@ -495,10 +495,10 @@ describe('Basic end-to-end Workflow', function () {

sh.exec(`${ngBin} build`);

var mainBundlePath = path.join(process.cwd(), 'dist', 'main.bundle.js');
var mainBundleContent = fs.readFileSync(mainBundlePath, { encoding: 'utf8' });
var stylesBundlePath = path.join(process.cwd(), 'dist', 'styles.bundle.js');
var stylesBundleContent = fs.readFileSync(stylesBundlePath, { encoding: 'utf8' });

expect(mainBundleContent.includes(testStyle)).to.be.equal(true);
expect(stylesBundleContent.includes(testStyle)).to.be.equal(true);
});

it('styles.css supports css imports', function() {
Expand All @@ -508,16 +508,62 @@ describe('Basic end-to-end Workflow', function () {
let testStyle = 'body { background-color: blue; }';
fs.writeFileSync(importedStylePath, testStyle, 'utf8');

let stylesPath = path.join(process.cwd(), 'src', 'style.css');
let importStyle = '@import \'./imported-style.css\';';
let stylesPath = path.join(process.cwd(), 'src', 'styles.css');
let importStyle = '@import \'./imported-styles.css\';';
fs.writeFileSync(stylesPath, importStyle, 'utf8');

sh.exec(`${ngBin} build`);

var mainBundlePath = path.join(process.cwd(), 'dist', 'main.bundle.js');
var mainBundleContent = fs.readFileSync(mainBundlePath, { encoding: 'utf8' });
var stylesBundlePath = path.join(process.cwd(), 'dist', 'styles.bundle.js');
var stylesBundleContent = fs.readFileSync(stylesBundlePath, { encoding: 'utf8' });

expect(stylesBundleContent).to.include(testStyle);
});

it('build supports global styles and scripts', function() {
this.timeout(420000);

sh.exec('npm install bootstrap@next', { silent: true });

const configFile = path.join(process.cwd(), 'angular-cli.json');
let originalConfigContent = fs.readFileSync(configFile, { encoding: 'utf8' });
let configContent = originalConfigContent.replace('"styles.css"', `
"styles.css",
"../node_modules/bootstrap/dist/css/bootstrap.css"
`).replace('"scripts": [],',`
"scripts": [
"../node_modules/jquery/dist/jquery.js",
"../node_modules/tether/dist/js/tether.js",
"../node_modules/bootstrap/dist/js/bootstrap.js"
],
`);

fs.writeFileSync(configFile, configContent, 'utf8');

sh.exec(`${ngBin} build`);

expect(mainBundleContent.includes(testStyle)).to.be.equal(true);
// checking for strings that are part of the included files
const stylesBundlePath = path.join(process.cwd(), 'dist', 'styles.bundle.js');
const stylesBundleContent = fs.readFileSync(stylesBundlePath, { encoding: 'utf8' });
expect(stylesBundleContent).to.include('* Bootstrap ');

const scriptsBundlePath = path.join(process.cwd(), 'dist', 'scripts.bundle.js');
const scriptsBundleContent = fs.readFileSync(scriptsBundlePath, { encoding: 'utf8' });
expect(scriptsBundleContent).to.include('* jQuery JavaScript');
expect(scriptsBundleContent).to.include('/*! tether ');
expect(scriptsBundleContent).to.include('* Bootstrap ');

// check the scripts are loaded in the correct order
const indexPath = path.join(process.cwd(), 'dist', 'index.html');
const indexContent = fs.readFileSync(indexPath, { encoding: 'utf8' });
let scriptTags = '<script type="text/javascript" src="inline.js"></script>' +
'<script type="text/javascript" src="styles.bundle.js"></script>' +
'<script type="text/javascript" src="scripts.bundle.js"></script>' +
'<script type="text/javascript" src="main.bundle.js"></script>'
expect(indexContent).to.include(scriptTags);

// restore config
fs.writeFileSync(configFile, originalConfigContent, 'utf8');
});

it('Serve and run e2e tests on dev environment', function () {
Expand Down