Skip to content
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

Enhancement: TS compiles only dependencies instead of entire project #1378

Closed
wants to merge 3 commits 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ npm-debug.log
/dist/**
/.awcache
.webpack.json
*.temp.json
/compiled/
dll/

Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ go to [http://0.0.0.0:3000](http://0.0.0.0:3000) or [http://localhost:3000](http
* [Configuration](#configuration)
* [AoT Don'ts](#aot-donts)
* [External Stylesheets](#external-stylesheets)
* [Lazy Loading](#lazy-loading)
* [Contributing](#contributing)
* [TypeScript](#typescript)
* [@Types](#types)
Expand Down Expand Up @@ -240,11 +241,23 @@ The following are some things that will make AoT compile fail.
Any stylesheets (Sass or CSS) placed in the `src/styles` directory and imported into your project will automatically be compiled into an external `.css` and embedded in your production builds.

For example to use Bootstrap as an external stylesheet:

1) Create a `styles.scss` file (name doesn't matter) in the `src/styles` directory.
2) `npm install` the version of Boostrap you want.
3) In `styles.scss` add `@import 'bootstrap/scss/bootstrap.scss';`
4) In `src/app/app.module.ts` add underneath the other import statements: `import '../styles/styles.scss';`

# Lazy Loading
When you lazy load a module in your router config, it will go into a separate chunk and the browser won't download the code until the user attempts to navigate to the route.

You can make a module lazy load by using the `loadChildren` syntax in your route definitions:

```js
{ path: 'detail', loadChildren: './+detail#DetailModule'}
```

To make sure TypeScript compiles your lazy-loaded modules, declare them in `./src/app/lazy-loaded.ts` with an import statement. Declaring the modules allows TypeScript to only compile the necessary files. Previously TS would compile every single `.ts` file in your project tree on every single build which was inefficient and lead to issues.

# Contributing
You can include more examples as components but they must introduce a new concept such as `Home` component (separate folders), and Todo (services). I'll accept pretty much everything so feel free to open a Pull-Request

Expand Down
35 changes: 35 additions & 0 deletions config/specify-ts-files-plugin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Plugin: SpecifyTsFilesPlugin
*
* By default TypeScipt will compile every single .ts file in your project tree.
* This is inefficient and leads to problems. This plugin specifies your Webpack
* entries and any other files you pass in as "files" and writes them to a temporary
* tsconfig.json to use for your build. Only the entry files you pass in and their
* dependencies will get compiled. This makes builds faster and avoids issues.
*/
'use strict';
const fs = require('fs');
const path = require('path');

function SpecifyTsFilesPlugin(options) {
this.root = options.root || process.cwd();
this.entry = options.entry;
this.otherFilesToCompile = options.otherFilesToCompile || [];
this.tsConfigBase = options.tsConfigBase || 'tsconfig.json';
this.customTsConfigFileName = options.customTsConfigFileName || 'tsconfig.temp.json';
}

SpecifyTsFilesPlugin.prototype.apply = function(compiler) {
if(!this.entry || typeof this.entry !== 'object') {
throw new Error('SpecifyTsFilesPlugin Error: entry was not specified');
}
const allFilesToCompile = Object.keys(this.entry)
.map(key => this.entry[key])
.concat(this.otherFilesToCompile);
const baseConfigData = require(path.join(this.root, this.tsConfigBase));
const tsConfigContent = Object.assign({}, baseConfigData, {files: allFilesToCompile});
const customConfigFilePath = path.join(this.root, this.customTsConfigFileName);
fs.writeFileSync(customConfigFilePath, JSON.stringify(tsConfigContent));
};

module.exports = SpecifyTsFilesPlugin;
43 changes: 35 additions & 8 deletions config/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const InlineManifestWebpackPlugin = require('inline-manifest-webpack-plugin');
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const ngcWebpack = require('ngc-webpack');
const SpecifyTsFilesPlugin = require('./specify-ts-files-plugin');

/**
* Webpack Constants
Expand All @@ -42,6 +43,25 @@ const METADATA = {
*/
module.exports = function (options) {
isProd = options.env === 'production';

const entry = {
'polyfills': './src/polyfills.browser.ts',
'main': AOT ? './src/main.browser.aot.ts' :
'./src/main.browser.ts'
};

const otherFilesToCompile = [
'./src/app/app.module.ts',
'./src/app/lazy-loaded.ts'
];

const tsConfigBase = 'tsconfig.webpack.json';
const customTsConfigFileName = 'tsconfig.build.temp.json';

const atlConfig = {
configFileName: customTsConfigFileName
};

return {

/**
Expand All @@ -59,13 +79,7 @@ module.exports = function (options) {
*
* See: http://webpack.github.io/docs/configuration.html#entry
*/
entry: {

'polyfills': './src/polyfills.browser.ts',
'main': AOT ? './src/main.browser.aot.ts' :
'./src/main.browser.ts'

},
entry: entry,

/**
* Options affecting the resolving of modules.
Expand Down Expand Up @@ -381,10 +395,23 @@ module.exports = function (options) {

new ngcWebpack.NgcWebpackPlugin({
disabled: !AOT,
tsConfig: helpers.root('tsconfig.webpack.json'),
tsConfig: helpers.root(customTsConfigFileName),
resourceOverride: helpers.root('config/resource-override.js')
}),

/**
* Plugin: SpecifyTsFilesPlugin
* Description: Generates a temporary tsconfig.json which specifies all the entry files to compile.
* This prevents TypeScript from having to compile every single .ts file in the project tree.
*/
new SpecifyTsFilesPlugin({
root: helpers.root('.'),
entry: entry,
otherFilesToCompile: otherFilesToCompile,
tsConfigBase: tsConfigBase,
customTsConfigFileName: customTsConfigFileName
}),

/**
* Plugin: InlineManifestWebpackPlugin
* Inline Webpack's manifest.js in index.html
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"clean:aot": "npm run rimraf -- compiled",
"clean:dist": "npm run rimraf -- dist",
"clean:install": "npm set progress=false && npm install",
"clean": "npm cache clean && npm run rimraf -- node_modules doc coverage dist compiled dll",
"clean": "npm cache clean && npm run rimraf -- node_modules doc coverage dist compiled dll *.temp.json",
"docker": "docker",
"docs": "npm run typedoc -- --options typedoc.json --exclude '**/*.spec.ts' ./src/",
"e2e:live": "npm-run-all -p -r server:prod:ci protractor:live",
Expand Down
7 changes: 7 additions & 0 deletions src/app/lazy-loaded.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Declare your lazy loaded modules here to ensure they are processed by the TypeScript compiler
*/
import './+barrel';
import './+barrel/+child-barrel';
import './+detail';
import './+detail/+child-detail';
1 change: 1 addition & 0 deletions src/main.browser.aot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* Angular bootstrapping
*/
/// <reference path="./custom-typings.d.ts" />
import { platformBrowser } from '@angular/platform-browser';
import { decorateModuleRef } from './app/environment';
/**
Expand Down
1 change: 1 addition & 0 deletions src/main.browser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* Angular bootstrapping
*/
/// <reference path="./custom-typings.d.ts" />
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { decorateModuleRef } from './app/environment';
import { bootloader } from '@angularclass/hmr';
Expand Down
6 changes: 0 additions & 6 deletions tsconfig.webpack.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@
"node"
]
},
"exclude": [
"node_modules",
"dist",
"src/**/*.spec.ts",
"src/**/*.e2e.ts"
],
"awesomeTypescriptLoaderOptions": {
"forkChecker": true,
"useWebpackText": true
Expand Down
1 change: 1 addition & 0 deletions tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"no-forward-ref": true,
"no-input-rename": true,
"no-output-rename": true,
"no-reference": false,
"pipe-naming": [true, "camelCase", "my"],
"templates-use-public": true,
"use-host-property-decorator": true,
Expand Down