This post will explain how to create angular project from scratch with webpack and only dependencies, files, loaders and plugins which are really required.
Let’s start
Create folders and files
npm init -y to generate package.json.
This file contains project’s meta-data, dependency list and custom script commands
{
"name": "tem",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"tsc": "tsc",
"start": "webpack serve",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Install dependencies
npm i -S @angular/common @angular/compiler @angular/core @angular/router @angular/platform-browser @angular/platform-browser-dynamic rxjs zone.js
Dependencies
| Package | Description |
|---|---|
| @angular/common | Contains angular’s built in components, directives, etc (ngIf, ngFor) |
| @angular/compiler | Compiles code to browser runnable |
| @angular/core | Contains angular’s ngModule, Component, @ViewChild etc |
| @angular/router | For routing (pages) |
| @angular/platform-browser | Provides services that are essential to launch and run a browser app |
| @angular/platform-browser-dynamic | To bootstrap app for browser |
| rxjs | Contains Observable, Subject, Operators etc. |
| zone.js | Angular uses internally to detect changes etc. |
Install dev dependencies
npm i -D @angular/compiler-cli @ngtools/webpack css-loader html-loader html-webpack-plugin mini-css-extract-plugin postcss postcss-loader postcss-preset-env sass sass-loader to-string-loader typescript webpack webpack-cli webpack-dev-server
| Package | Description |
|---|---|
| @angular/compiler-cli | Angular uses internally for AOT compiling |
| @ngtools/webpack | Contains angular compiler plugin for webpack |
| css-loader | Used to process css files |
| html-loader | Used to process html files |
| html-webpack-plugin | Help injecting bundles |
| mini-css-extract-plugin | Extract css into its own file |
| postcss | Used to add collection of css plugin/loaders |
| postcss-loader | Used to add postcss plugin |
| postcss-preset-env | Plugin for adding auto-prefixer and optimization |
| sass | Used to convert sass to css |
| sass-loader | Used to add sass plugin |
| to-string-loader | convert css to string |
| typescript | used to transpile typescript to javascript |
| webpack | Used to bundle code |
| webpack-cli | Webpack uses internally |
| webpack-dev-server | Used for development for server |
npm run tsc -- --init to generate tsconfig.json
- Make sure to add
tscas script in package.json scripts object (See above) - Update tsconfig
target,moduleandmoduleResolutionin order to work lazy load.
{
...
"target": "ES2015",
"module": "ES2020",
"moduleResolution": "node",
...
}
All other files have to be created manually
project
│ package.json
│ tsconfig.json
│ angular.json
│ webpack.config.js
└───src
│ │ main.ts
│ │ polyfills.ts
│ │ index.html
│ │ styles.scss
│ └───app
│ │ app.module.ts
│ │ app-routing.module.ts
│ │ app.component.ts
│ │ app.component.html
│ │ app.component.scss
│ └───environments
│ │ environment.ts
│ │ environment.prod.ts
Add content to the files
angular.json
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"sample": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"skipTests": true,
"style": "scss"
},
"@schematics/angular:directive": {
"skipTests": true
},
"@schematics/angular:guard": {
"skipTests": true
},
"@schematics/angular:pipe": {
"skipTests": true
},
"@schematics/angular:service": {
"skipTests": true
}
},
"prefix": "app",
"architect": {}
}
},
"defaultProject": "sample",
"cli": {
"packageManager": "npm"
}
}
webpack.config.js
const path = require('path');
const sass = require('sass');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin;
module.exports = (env) => {
const isDevelopment = env.WEBPACK_SERVE || false;
const sassOptions = [
{
loader: 'css-loader',
options: { esModule: false }
},
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{ autoprefixer: { grid: true } },
]
],
},
},
},
{
loader: 'sass-loader',
options: { implementation: sass }
}
];
const config = {
mode: isDevelopment ? 'development' : 'production',
resolve: {
extensions: ['.ts', '.js']
},
entry: {
main: './src/main',
styles: './src/styles.scss'
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].[fullhash].bundle.js',
chunkFilename: '[id].[fullhash].chunk.js'
},
module: {
rules: [
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
loader: '@ngtools/webpack'
},
{
test: /\.html$/,
loader: 'html-loader',
exclude: path.resolve('./src/index.html')
},
{
test: /\.scss$/,
use: [
'to-string-loader',
...sassOptions
],
exclude: /styles\.scss/
},
{
test: /styles\.scss/,
use: [
MiniCssExtractPlugin.loader,
...sassOptions
]
}
]
},
optimization: {
minimizer: [`...`],
},
plugins: [
new MiniCssExtractPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
chunks: ['main', 'styles'],
chunksSortMode: 'manual',
inject: 'body',
base: '/'
}),
new AngularCompilerPlugin({
tsConfigPath: path.resolve('tsconfig.json'),
mainPath: './src/main.ts',
hostReplacementPaths: {
'./src/environments/environment.ts':
isDevelopment ?
'./src/environments/environment.ts' :
'./src/environments/environment.prod.ts'
}
})
]
}
if (isDevelopment) {
config.output.filename = '[name].bundle.js';
config.output.chunkFilename = '[id].bundle.js';
config.target = 'web';
config.devtool = 'eval-source-map';
config.stats = {
preset: 'minimal'
};
config.devServer = {
open: true,
overlay: true,
hot: true,
liveReload: false,
writeToDisk: env.writeToDisk,
};
config.optimization = { runtimeChunk: 'single' };
/**Config for styles.scss */
config.module.rules[3].use.splice(0, 1, 'style-loader');
}
return config;
}
main.ts
import './polyfills';
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
declare const module: { hot: { accept: () => void; }; };
if (environment.production) {
enableProdMode();
}
if (module.hot) {
module.hot.accept();
}
platformBrowserDynamic().bootstrapModule(AppModule);
polyfills.ts
import 'zone.js/dist/zone';
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Angular from scratch with webpack</title>
</head>
<body>
<app-root></app-root>
</body>
</html>
styles.scss
html, body { height: 100%; }
body { margin: 0 }
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppComponent } from './app.component';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule
],
bootstrap: [AppComponent]
})
export class AppModule { }
app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [
RouterModule.forRoot(routes, { useHash: true }),
],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent { }
app.component.html
<h1>App component works</h1>
environment.ts
export const environment = {
production: false
};
environment.prod.ts
export const environment = {
production: true
};
Let’s test development, Run
npm start
Development working as expected!
Let’s test production, Run
npm run build
Production working as expected!
Some Details
main.ts
if (module.hot) {
module.hot.accept();
}
Above code will listen for hot update from webpack and accept the new changes.
environment.ts will be replaced with environment.prod.ts
As you can see production value will be updated in production compilation so that angular will minimize and optimize code.
You can also add other properties which you want to keep different in production
Comments
Post a Comment