We have an Angular 4
project that I've recently tried to upgrade to Angular 8
. I followed the migration guide in Angular website, changed some of the syntaxes, and everything preventing project to be built. I faced the problem of my styles were not loading properly locally and not at all on Azure.
I found Webpack
and tried to configure it, added style-loader, sass-loader, and css-loader.
Now when I'm running locally, I can see in the network tab in the browser that all styles are loading properly, but it only loads the default index.html file and not bootstrapping the application.
When I deploy the app on Azure, it loads other components, but none of the styles are loading. I spent 3 weeks on migration, nothing promising yet.
Tools/Plugins version:
Angular CLI: 8.3.5
Node: 10.15.1
OS: win32 x64
Angular: 8.2.7
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... platform-server, router
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.803.5
@angular-devkit/build-angular 0.803.5
@angular-devkit/build-optimizer 0.803.5
@angular-devkit/build-webpack 0.803.5
@angular-devkit/core 8.3.5
@angular-devkit/schematics 8.3.5
@angular/cdk 8.2.0
@angular/cli 8.3.5
@angular/http 5.2.11
@angular/material 8.2.0
@ngtools/webpack 8.3.5
@schematics/angular 8.3.5
@schematics/update 0.803.5
rxjs 6.5.3
typescript 3.5.3
webpack 4.40.2
Here is my Webpack config:
const { resolve } = require('path');
const rxPaths = require('rxjs/_esm5/path-mapping');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const { AngularCompilerPlugin } = require('@ngtools/webpack');
const { IndexHtmlWebpackPlugin } = require('@angular-devkit/build-angular/src/angular-cli-files/plugins/index-html-webpack-plugin');
module.exports = {
mode: 'development',
devtool: 'eval',
entry: {
main: './src/main.ts',
polyfills: './src/polyfills.ts',
styles: './src/styles.scss'
},
output: {
path: resolve('./dist/'),
filename: '[name].js',
},
resolve: {
extensions: ['.ts', '.js'],
alias: rxPaths()
},
node: false,
performance: {
hints: false,
},
module: {
rules: [
{
test: /\.ts$/,
use: '@ngtools/webpack'
},
{
test: /\.js$/,
exclude: /(ngfactory|ngstyle).js$/,
enforce: 'pre',
use: 'source-map-loader'
},
{
test: /\.html$/,
use: 'raw-loader'
},
{
test: /\.s[ac]ss$/i,
use: ['sass-loader'],
// use: ['to-string-loader, css-loader, sass-loader'],
exclude: [resolve('./src/styles.scss')]
},
{
test: /\.s[ac]ss$/i,
// use: ['sass-loader'],
include: [resolve('./src/styles.scss')]
},
{
test: /\.(eot|svg|cur)$/,
loader: 'file-loader',
options: {
name: `[name].[ext]`,
limit: 10000
}
},
{
test: /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/,
loader: 'url-loader',
options: {
name: `[name].[ext]`,
limit: 10000
}
},
// This hides some deprecation warnings that Webpack throws
{
test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
}
]
},
plugins: [
new IndexHtmlWebpackPlugin({
input: 'index.html',
output: 'index.html',
inject: 'body',
entrypoints: [
'styles',
'polyfills',
'main'
]
}),
new AngularCompilerPlugin({
mainPath: resolve('./src/main.ts'),
sourceMap: true,
nameLazyFiles: true,
tsConfigPath: resolve('./src/tsconfig.app.json')
// ,
// skipCodeGeneration: true
}),
new ProgressPlugin(),
new CircularDependencyPlugin({
exclude: /[\\\/]node_modules[\\\/]/
}),
new CopyWebpackPlugin([
{
from: 'src/assets',
to: 'assets'
},
{
from: 'src/favicon.ico'
}
])
]
};
Please note that the reason I've commented use[] in Webpack config was that it was throwing some postcss-loader exception and on an issue on Github found that some conflict will occur with default sass-loader and Webpack and you should remove them.
Here is the build config in angular.json
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.config.js",
"replaceDuplicatePlugins": true
},
"outputPath": "./dist/",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"assets": [
"src/assets",
"src/config",
"src/favicon.ico"
],
"styles": [
"./src/styles.scss"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js",
"node_modules/metismenu/dist/metisMenu.js",
"node_modules/vis/dist/vis.min.js",
"vendor/js/jvectormap/jquery-jvectormap-2.0.2.min.js",
"vendor/js/jvectormap/jquery-jvectormap-us-mill.js",
"vendor/js/iCheck/icheck.js",
"node_modules/toastr/toastr.js"
]
},
"configurations": {
"dev": {
"optimization": true,
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
]
},
"local": {
"optimization": true,
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
},
"production": {
"optimization": true,
"sourceMap": false,
"extractCss": false,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"styles": [
"./src/styles.scss"
]
}
}
},
And here is the serve config in Angular.json.
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "projectName:build",
"customWebpackConfig": {
"path": "./webpack.config.js"
}
},
"configurations": {
"local":{
"browserTarget": "projectName:build:local"
}
,
"dev": {
"browserTarget": "projectName:build:dev"
},
"production": {
"browserTarget": "projectName:build:production"
}
}
},
I have imported all styles in styles.scss using @import statements. Just one thing I am not sure about is that I'm using Highcharts and getting some warnings during the build.
WARNING in ./node_modules/angular2-highcharts/dist/index.js
Module Warning (from ./node_modules/source-map-loader/index.js):
(Emitted value instead of an instance of Error) Cannot find source file '../src/index.ts': Error: Can't resolve '../src/index.ts'
Other than these, there is not compile/runtime error in the project.
Thank you for taking the time to read my problem. I appreciate any hint/tip.
Update: This is how the project structure looks like:
| .editorconfig
| .gitignore
| angular.json
| browserslist
| karma.conf.js
| package-lock.json
| package.json
| protractor.conf.js
| README.md
| tsconfig.json
| tslint.json
| webpack.config.js
|
+---src
| | favicon.ico
| | index.html
| | index.js
| | main.ts
| | polyfills.ts
| | styles.scss
| | test.ts
| | tsconfig.app.json
| | tsconfig.spec.json
| | typings.d.ts
| | webpack.config.common.js
| |
| +---app
| +---assets
| | |
| | +---images
| | \---styles
| | | style.scss
| | |
| |
| +---config
| | dev-config.js
| | local-config.js
| | prod-config.js
| | qa-config.js
| |
| +---environments
| | environment.dev.ts
| | environment.prod.ts
| | environment.qa.ts
| | environment.ts
The file index.ts is missing from the project it seems that the file index.js extension was changed from ts to js and it is looking for it as ts.
Try with changing the index.js extension with index.ts in the src folder.
If I understood correctly, the main problem is that styles are not applied.
You are using Bootstrap files according to this row of your config: "node_modules/bootstrap/dist/js/bootstrap.min.js"
, however you have not imported this styles into final bundle. So try to write this into angular.json
file:
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.scss"
],
In addition, you need to import bootstrap
styles to use them in your application into style.scss
file:
/* You can add global styles to this file, and also import other style files */
@import "~bootstrap/dist/css/bootstrap.css";
<!--
h1, h2, h3 {
margin-bottom: 1.5rem;
}
-->
UPDATE:
Our app.module.ts
should look like this after creating through Angular CLI:
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Every application should have a start place. In Angular, we have a convention, that our application should start at AppModule
. AppModule
is our rout module. So we are telling to Angular that when it creates our root module(AppModule
) at start that we want to set AppComponent
as a starting point(bootstrap
) into the DOM.
The code that will bootstrap your application placed into main.ts
file:
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
The above code uses Just in Time compilation.
Let me show how index.html
looks:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Frontend</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
Where <app-root></app-root>
is a selector for app.component.ts
:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'Frontend';
test = {};
}
You can change the default page to show by replacing by the selector of your component in the index.html
.
Double check your selector of app.component.html
and selector used in in your index.html
.
Try to set projectName to your name of project in the serve
section of angular.json
file. For example, if your project is named as superappl
, then you should write like this:
serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "superappl:build",
"customWebpackConfig": {
"path": "./webpack.config.js"
}
},
"configurations": {
"local":{
"browserTarget": "superappl:build:local"
}
,
"dev": {
"browserTarget": "superappl:build:dev"
},
"production": {
"browserTarget": "superappl:build:production"
}
}
},
If above actions will not run your application. Then I suggest you to create new brand application using Angular CLI
and compare your index.html
file and app.module.ts
files. Commands to create new brand application to compare your existing application (especially, package.json
and angular.json
files):
npm install -g @angular/cli
ng new angular-newapp --skip-install
npm install @angular/core@latest
npm install @angular/http@latest
npm install
ng serve
Some questions:
Have you created manually Webpack.config
? What's reason to use it? You can avoid using and tuning Webpack config
if it is applicable to you. As Angular CLI by default does not create this file. You should manually write ng-eject
command to get webpack file.
Can you post your index.html
and app.module.ts
?
ng serve
?If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With