grunt webpack Cannot find module 'webpack-dev-server' - gruntjs

I have a grunt setup to bundle my react files using webpack and grunt-webpack. I am not using webpack-dev-server but still my grunt is outputting error as Cannot find module 'webpack-dev-server'
Here is my grunt file:
var webpack = require("webpack");
var webpackConfig = require("./webpack.config.js");
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt);
grunt.loadNpmTasks("grunt-webpack");
grunt.initConfig({
eslint: {
options: {
configFile: 'eslint.json'
},
target: ['./react/components/**/*.js','./react/services/**/*.js', './node/source/**/*.js']
},
webpack: {
options: webpackConfig,
build:{}
},
watch: {
app: {
files: ['./react/main.js', './react/components/**/*.js','./react/services/**/*.js'],
tasks: ["webpack"],
options: {
spawn: false,
}
}
}
});
grunt.registerTask('lint', ['eslint']);
grunt.registerTask('build', ['webpack']);
grunt.registerTask('default', ['watch']);
};
webpack.config.js file
const path = require('path');
const buildDirectory = './node/static/js/';
module.exports = {
entry: './react/main.js',
resolve: {
extensions: ['', '.js', '.jsx'],
},
output: {
path: path.resolve(buildDirectory),
filename: 'bundle.js',
},
externals: {
'cheerio': 'window',
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true,
},
stats: {
assets: false,
colors: false,
modules: false,
version: false,
hash: false,
timings: false,
chunks: false,
chunkModules: false
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['react', 'es2015'],
},
}],
},
plugins: [],
};
Error output
grunt build
Loading "webpack-dev-server.js" tasks...ERROR
>> Error: Cannot find module 'webpack-dev-server'
Loading "webpack-dev-server.js" tasks...ERROR
>> Error: Cannot find module 'webpack-dev-server'
Running "webpack:build" (webpack) task
Done.
This error gets resolved if I add webpack-dev-server package, but I don't want extra dependency in my project.
Packages:
"webpack": "^1.13.1",
"grunt-webpack": "^1.0.14",
"grunt": "^1.0.1",
"grunt-contrib-watch": "^1.0.0",
"grunt-eslint": "^19.0.0",

You will have to add it as dependency. Why you don't need it anyway; it seems necessary to in order to run the project in development. That's way NPM allows you to have development dependencies as well. All of the ones that you listed are dev dependencies.
See below:
"devDependencies": {
// ... more dev dependencies
"webpack-dev-server": "^1.14.1"
},
"dependencies": {
// ... more 'normal' dependencies
"bootstrap": "^3.3.6"
}

Related

Angular 5/ASP.NET - “No ResourceLoader implementation has been provided. Can't read the URL”

I'm trying to build a new Angular5/ASP.NET SPA on Visual Studio 2017. Therefore i created a .NET Core->ASP.NET Core-Web Application with Angular, which results in a project containing an Angular4 sample application.
Running this application is no problem at all, the problems start when i try to go on Angular 5 (5.0.1 or 5.0.0, does not matter) with this application.
After doing all necessary steps, the app runs fine in Debug mode. But trying to build and start it in Release (or deploy it to azure) leads to the following error:
An unhandled exception occurred while processing the request.
NodeInvocationException: No ResourceLoader implementation has been provided. Can't read the url "app.component.html"
Error: No ResourceLoader implementation has been provided. Can't read the url "app.component.html"
at Object.get (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:98069:15)
at DirectiveNormalizer.module.exports.DirectiveNormalizer._fetch (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:44087:43)
at DirectiveNormalizer.module.exports.DirectiveNormalizer._preParseTemplate (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:44142:29)
at DirectiveNormalizer.module.exports.DirectiveNormalizer.normalizeTemplate (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:44122:36)
at CompileMetadataResolver.module.exports.CompileMetadataResolver.loadDirectiveMetadata (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:55794:75)
at E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:74510:72
at Array.forEach (native)
at E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:74509:72
at Array.forEach (native)
at JitCompiler.module.exports.JitCompiler._loadModules (E:\angular4_spielwiese\vs spielwiese\myAngularApp\myAngularApp\ClientApp\dist\vendor.js:74506:75)
Microsoft.AspNetCore.NodeServices.HostingModels.HttpNodeInstance+<InvokeExportAsync>d__7.MoveNext()
What i do for moving to Angular5 is:
Change Versions in package.json for all Angular-Modules to 5.0.1, also go to newer version for typescript, rxjs, angular/cli and #ngtools/webpack (1.5.0 -> 1.8.0)
So my new package.json looks like this:
{
"name": "myAngularApp",
"private": true,
"version": "0.0.0",
"scripts": {
"test": "karma start ClientApp/test/karma.conf.js"
},
"dependencies": {
"#angular/animations": "^5.0.1",
"#angular/common": "^5.0.1",
"#angular/compiler": "^5.0.1",
"#angular/core": "^5.0.1",
"#angular/forms": "^5.0.1",
"#angular/http": "^5.0.1",
"#angular/platform-browser": "^5.0.1",
"#angular/platform-browser-dynamic": "^5.0.1",
"#angular/platform-server": "^5.0.1",
"#angular/router": "^5.0.1",
"#types/webpack-env": "^1.13.0",
"angular2-template-loader": "^0.6.2",
"aspnet-prerendering": "^3.0.1",
"aspnet-webpack": "^2.0.1",
"awesome-typescript-loader": "^3.2.1",
"bootstrap": "^3.3.7",
"css": "^2.2.1",
"css-loader": "^0.28.7",
"es6-shim": "^0.35.3",
"event-source-polyfill": "0.0.9",
"expose-loader": "^0.7.3",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.5",
"html-loader": "^0.5.1",
"html-webpack-plugin": "^2.30.1",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.2.1",
"json-loader": "^0.5.4",
"preboot": "^5.1.7",
"raw-loader": "^0.5.1",
"reflect-metadata": "^0.1.10",
"rxjs": "^5.5.2",
"style-loader": "^0.19.0",
"to-string-loader": "^1.1.5",
"typescript": "^2.6.1",
"zone.js": "^0.8.18"
},
"devDependencies": {
"#angular/cli": "1.5.0",
"#angular/compiler-cli": "^5.0.1",
"#ngtools/webpack": "1.8.0",
"#types/chai": "4.0.1",
"#types/jasmine": "2.6.3",
"chai": "4.0.2",
"jasmine-core": "2.6.4",
"karma": "1.7.0",
"karma-chai": "0.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-jasmine": "1.1.0",
"karma-webpack": "2.0.3",
"url-loader": "0.6.2",
"webpack": "3.8.1",
"webpack-hot-middleware": "2.20.0",
"webpack-merge": "4.1.1"
}
}
Then i change AotPlugin in webpack.config.js to AngularCompilerPlugin
This is my webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AngularCompilerPlugin = require('#ngtools/webpack').AngularCompilerPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] },// '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
When i now start the application (performing npm install, then run webpack with --env.prod switch) with Release-config out of VS2017 i get the stacktrace above. The same thing happens when i deploy the application to Azure.
On localhost if i wait a few seconds and force-reload my browser, the application suddenly works. This does not work on Azure, which is kinda strange to me.
Do you have any suggestions what i might have done wrong or what i am missing?
I had the same issues for few days, I found a VS2017 - Angular 5 project in GitHub (don't have the exact URL), from which I have copied the webpack.config.js
I have also updated my Angular to 5.0.3
I than ran the 'dotnet publish' which worked (or 'dotnet publish -c Release')
The only problem I faced (and still facing) is during the complication, the compiler messes up the main-server.js, so as a workaround I have copied the main-server.js before the complication (10MB vs 2MB).
When running 'dotnet mydll.dll' - works great.
The webpack.config.js:
/*
* Webpack (JavaScriptServices) with a few changes & updates
* - This is to keep us inline with JSServices, and help those using that template to add things from this one
*
* Things updated or changed:
* module -> rules []
* .ts$ test : Added 'angular2-router-loader' for lazy-loading in development
* added ...sharedModuleRules (for scss & font-awesome loaders)
*/
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AngularCompilerPlugin = require('#ngtools/webpack').AngularCompilerPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
//const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: { modules: false },
context: __dirname,
resolve: { extensions: ['.js', '.ts'] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize'] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' } ]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// new BundleAnalyzerPlugin(),
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'),
exclude: ['./**/*.server.ts']
})
]),
devtool: isDevBuild ? 'cheap-eval-source-map' : false,
node: {
fs: "empty"
}
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
// resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
}),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'),
{}
)
].concat(isDevBuild ? [] : [
new webpack.optimize.UglifyJsPlugin({
compress: false,
mangle: false
}),
// Plugins that apply in production builds only
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
// switch to "inline-source-map" if you want to debug the TS during SSR
devtool: isDevBuild ? 'cheap-eval-source-map' : false
});
return [clientBundleConfig, serverBundleConfig];
};
EDIT -
In addition to the changes on the webpack.config.js, I did the following two changes which solved my problem!:
In index.cshtml:
change from
<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
to:
<app>Loading...</app>
In boot.server.ts:
change from:
const zone = moduleRef.injector.get(NgZone);
to:
const zone: NgZone = moduleRef.injector.get(NgZone);
Read http://www.talkingdotnet.com/upgrade-angular-4-app-angular-5-visual-studio-2017/ for more info.

No NgModule metadata found for 'AppModule' Error in Angular 5 server-side rendering with --env.prod

I'm trying to upgrade an ASP.NET Core + Angular 4 SPA project from .NET Core 2.0.0/Angular4 to .NET Core 2.0.3/Angular5. I managed to get everything working properly except for the server-side rendering in a production environment, i/e when I publish the app:
An unhandled exception has occurred: No NgModule metadata found for 'AppModule'.
Error: No NgModule metadata found for 'AppModule'.
The issue only happens when both of these two conditions are met:
Webpack builds the packages using the --env.prod switch
The Index.cshtml view file contains the asp-prerender-module parameter, just like in the following example:
<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
If I remove the switch and/or the parameter, the problem disappears (together with SSR).
There's a bunch of other info I can give:
It's not something related to IIS, it happens at Kestrel-level.
It's not related to the web server machine because I can even reproduce it with locally by manually launching Webpack with the --end.prod switch right before a Debug or Release run.
It doesn't seem to have anything to do with the source code, as I can reproduce it even with a single-component sample app with very basic AppModule files and trivial code.
The project was running perfectly fine with .NET Core 2.0.0 and Angular 4.3.x.
The only major thing I changed in the webpack.config.js file is replacing the AotPlugin with the new, Angular5-specific AngularCompilerPlugin provided by the #ngtools/webpack package: I think that might as well be the cause, as the --env.prod switch makes use of that AOT compiler instead of the JIT one. That, or something related to the .NET SpaServices package - maybe not on-par with the new Angular5 and/or the new AoT compiler?
Sadly, I can't revert to the former AotPlugin because it throws errors as well - which is perfectly understandable, as it's not meant to be used with Angular5.
Software Versions
.NET Core 2.0.3
Angular 5.0.2
#ngtools/webpack 1.8.2 (also tried with 1.8.1 - same outcome)
WebPack 2.6.1 (also tried with 2.5.6 - same outcome)
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AotPlugin = require('#ngtools/webpack').AngularCompilerPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
The #ngtool/webpack configuration for Angular 5 is somewhat different form Angular 2/4. So, I've changed the webpack.config.js as following,
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AngularCompilerPlugin = require('#ngtools/webpack').AngularCompilerPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' },
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js)$/,
loader: '#ngtools/webpack',
options: {
tsConfigPath: '/tsconfig.json',
}
}
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AngularCompilerPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
And here is my package.json file,
{
"dependencies": {
"#angular/animations": "^5.0.2",
"#angular/cdk": "^5.0.0-rc0",
"#angular/cli": "^1.6.0-beta.2",
"#angular/common": "^5.0.2",
"#angular/compiler": "^5.0.2",
"#angular/compiler-cli": "^5.0.2",
"#angular/core": "^5.0.2",
"#angular/forms": "^5.0.2",
"#angular/http": "^5.0.2",
"#angular/material": "^5.0.0-rc0",
"#angular/platform-browser": "^5.0.2",
"#angular/platform-browser-dynamic": "^5.0.2",
"#angular/platform-server": "^5.0.2",
"#angular/router": "^5.0.2",
"#ngtools/webpack": "^1.8.3",
"#types/webpack-env": "^1.13.2",
"angular2-template-loader": "0.6.2",
"aspnet-prerendering": "^3.0.1",
"aspnet-webpack": "^2.0.1",
"awesome-typescript-loader": "^3.4.0",
"bootstrap": "3.3.7",
"css": "2.2.1",
"css-loader": "^0.28.7",
"es6-shim": "0.35.3",
"event-source-polyfill": "0.0.12",
"expose-loader": "0.7.4",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.5",
"html-loader": "^0.5.1",
"isomorphic-fetch": "2.2.1",
"jquery": "3.2.1",
"json-loader": "^0.5.7",
"preboot": "^5.1.7",
"raw-loader": "0.5.1",
"reflect-metadata": "0.1.10",
"request": "^2.83.0",
"rxjs": "^5.5.2",
"style-loader": "^0.19.0",
"to-string-loader": "1.1.5",
"typescript": "^2.6.1",
"url-loader": "^0.6.2",
"webpack": "^3.8.1",
"webpack-hot-middleware": "^2.20.0",
"webpack-merge": "^4.1.1",
"zone.js": "^0.8.18"
},
"devDependencies": {
"#types/chai": "^4.0.5",
"#types/jasmine": "^2.8.2",
"#types/node": "^8.0.53",
"chai": "^4.1.2",
"jasmine-core": "2.8.0",
"karma": "1.7.1",
"karma-chai": "0.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-jasmine": "1.1.0",
"karma-webpack": "2.0.6"
},
"name": "aspnetcoreangularspa",
"private": true,
"scripts": {
"test": "karma start ClientApp/test/karma.conf.js"
},
"version": "0.0.0"
}
If you still having problems running the solution, please have a look at this repository for a working solution.
Hope it helps :)
As others suggested, the temporary solution is to remove the SSR (Server Side Rendering). That means opening the Home/Index.cshtml file and change
<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
to
<app>Loading...</app>
I found your Issue while searching for a solution to my problem described here:
https://github.com/aspnet/JavaScriptServices/issues/1388
So i tried your webpack-config and also tried to run the app from the repository, but when i do "dotnet publish" and then run the app i get this error:
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
An unhandled exception has occurred: No NgModule metadata found for 'AppModule'.
Error: No NgModule metadata found for 'AppModule'.
at NgModuleResolver.module.exports.NgModuleResolver.resolve
solution from mak0t0san working for me and ssr still working (angular 5.2.0),
update ngtoolwebpack to 1.10.2
typescript 2.6.2
and change webpack.config.js with that
const path = require('path');
const webpack = require('webpack');
const { DllReferencePlugin, SourceMapDevToolPlugin} = require('webpack');
const merge = require('webpack-merge');
const {AngularCompilerPlugin, PLATFORM} = require('#ngtools/webpack');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: {modules: false},
context: __dirname,
resolve: {extensions: ['.js', '.ts']},
output: {
filename: '[name].js',
chunkFilename:'[id].chunk.js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{test: /\.html$/, use: 'html-loader?minimize=false'},
{test: /\.css$/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize']},
{test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000'},
{
test: /\.(scss)$/,
use: [{
loader: 'style-loader', // inject CSS to page
}, {
loader: 'css-loader', // translates CSS into CommonJS modules
}, {
loader: 'postcss-loader', // Run post css actions
options: {
plugins: function () { // post css plugins, can be exported to postcss.config.js
return [
require('precss'),
require('autoprefixer')
];
}
}
}, {
loader: 'sass-loader' // compiles Sass to CSS
}]
}
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
module:{
rules:[
{
test: /\.ts$/,
use: ['#ngtools/webpack']
},
]
},
entry: {'main-client': './ClientApp/boot.browser.ts'},
output: {path: path.join(__dirname, clientBundleOutputDir)},
plugins: [
new DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
}),
new AngularCompilerPlugin({
"mainPath": path.join(__dirname, 'ClientApp/boot.browser.ts'),
platform: PLATFORM.Browser,
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.browser.module#AppModule'),
sourceMap: true
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new UglifyJsPlugin({
sourceMap: true
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
module:{
rules:[
{ test: /\.ts$/, use: ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] },
]
},
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
],
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
As written at the #MMiebach's link:
Angular 5 includes breaking changes (versus Angular 4) meaning that the code for server-side rendering has to be very different.
Luckily, Microsoft released their new SPA project template for Angular 5. It can be installed with
dotnet new --install Microsoft.DotNet.Web.Spa.ProjectTemplates::2.0.0
After that command dotnet new angular will use the 5th Angular instead of 4th.
By default, server-side rendering is not turned on, but there are instructions how to do it in Docs by MS.

Webpack source-map does not resolve sass imports

I have webpack configured to transpile scss -> css, but sourcemap generated by webpack does not resolve scss #imports.
webpack.config.js:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const outputPath = path.join(__dirname, 'dist');
module.exports = {
devtool: 'source-map',
entry: ['./src/main.scss'],
target: 'web',
output: {
filename: 'js/[name].bundle.js',
path: outputPath
},
module: {
rules: [
{ // sass / scss loader for webpack
test: /\.(sass|scss)$/,
loader: ExtractTextPlugin.extract([
{
loader: 'css-loader',
options: {
url: false,
import: true,
minimize: true,
sourceMap: true,
}
},
'sass-loader'
])
},
]
},
plugins: [
new ExtractTextPlugin({ // define where to save the file
filename: 'css/[name].bundle.css',
allChunks: true,
})
]
};
main.scss:
#import 'foo';
_foo.scss:
h1 { color: red; }
However, in Chrome dev tools, I see a reference to main.scss where I expect reference to _foo.scss - see the screenshot below:
Compiled demo: http://store.amniverse.net/webpacktest/
You should not use extractTextPlugin when you are in dev mode.
Please make extra configs for dev and production mode. In production the use of extractTextPlugin is fine but in dev mode it is not necessary and can lead to other features not working. So instead use the style-loader.
Also - I am not sure if that fixes your problem - try to use importLoaders prop on the css loader. Look here for more info:
https://github.com/webpack-contrib/css-loader#importloaders
const path = require('path');
const outputPath = path.join(__dirname, 'dist');
module.exports = {
devtool: 'source-map',
entry: ['./src/main.scss'],
target: 'web',
output: {
filename: 'js/[name].bundle.js',
path: outputPath
},
module: {
rules: [
{ // sass / scss loader for webpack
test: /\.(sass|scss)$/,
loader: [
{
loader: 'style-loader',
options: {
sourceMap: true
}
},
{
loader: 'css-loader',
options: {
url: false,
import: true,
minimize: true,
sourceMap: true,
importLoaders: 1,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
]
}
};
You have sass-loader there, switch it with:
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
And that would work.
There's nothing wrong with ExtractTextPlugin in dev mode, and what #Omri Aharon posted is correct. However, what you should consider is having source-map enabled only in dev mode.
To build webpack using its default production settings (which uglifies and applies OccurrenceOrderPlugin plugin by default in webpack 2.0+), run the command webpack -p, and then in your webpack.config.js, you can determine if you're in dev mode or not by doing:
const DEBUG = !process.argv.includes('-p');
Add the function
function cssConfig(modules) {
return {
sourceMap: DEBUG,
modules,
localIdentName: DEBUG ? '[name]_[local]_[hash:base64:3]' : '[hash:base64:4]',
minimize: !DEBUG
};
}
in your webpack.config.js, making your scss loader appear as so:
test: /\.(sass|scss)$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: cssConfig(true)
},
{
loader: 'sass-loader',
options: { sourceMap: DEBUG }
}
]
})
},
and my plugins section has
new ExtractTextPlugin('[name].css?[contenthash]'),

Ant Design error: "Unknown plugin 'import' specified in '[..]/.babelrc'"

I've put the following in my .babelrc:
{
"plugins": [
["import", { libraryName: "antd", style: "css" }] // `style: true` for less
]
}
This is the error:
Unknown plugin "import" specified in "[..]/.babelrc"
Additionally it's not clear to me from the docs whether I have to import the CSS for:
every single component (e.g. DatePicker) or
if antd/dist/antd.css includes just everything.
In case of 1. it would be nice to have the CSS paths as part of the examples.
In case of 2. where do I put that include, in my App.js?
These are the babel packages I have installed:
"babel-core": "^6.24.0",
"babel-eslint": "^7.2.1",
"babel-loader": "^6.4.1",
"babel-plugin-transform-class-properties": "^6.23.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-preset-es2015": "^6.24.0",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-0": "^6.22.0",
And this is my webpack.config.js:
const webpack = require('webpack');
const path = require('path');
const nodeModulesPath = path.resolve(__dirname, 'node_modules');
const config = {
// Render source-map file for final build
devtool: 'source-map',
// Entrypoint of the app, first JS to load
entry: [
path.join(__dirname, './app/index.js'),
],
output: {
path: path.resolve(__dirname, "build"), // absolute Path of output file
filename: 'bundle.js', // Name of output file
publicPath: '/static'
},
module: {
rules: [
{
test: /\.js$/, // All .js files
exclude: [nodeModulesPath],
use: [
{
loader: "babel-loader",
options: {
presets: [
"es2015",
"stage-0",
"react",
],
plugins: [
"transform-class-properties",
"transform-decorators-legacy"
]
}
}
]
}
]
},
plugins: [
// Define production build to allow React to strip out unnecessary checks
new webpack.DefinePlugin({
'process.env':{
'NODE_ENV': JSON.stringify('development')
}
}),
// Suppress all the "Condition always true" warnings
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
minimize: true,
}),
],
};
module.exports = config;
Install babel-plugin-import You can see docs in https://github.com/ant-design/babel-plugin-import

Webpack ignores sass files

I'm using webpack for a project. It compiles the typescript fine, however, it seems to ignore the sass files. The sass files are stored in the './build/sass' of the project directory.
When running webpack the output is:
Hash: dc64dbebfd6ff9cb2a38
Version: webpack 1.13.2
Time: 1201ms
Asset Size Chunks Chunk Names
bundle.js 1.7 kB 0 [emitted] app
[0] multi app 28 bytes {0} [built]
+ 1 hidden modules
So it runs fine. You can find the webpack.config.js below:
require('dotenv').load()
var webpack = require("webpack"),
path = require('path'),
ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
context: __dirname,
entry: {
app: [
path.join(__dirname, 'build', 'js', 'app')
]
},
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'public'),
publicPath: '/',
},
resolve: {
extensions: ['', '.ts', '.js'],
modulesDirectories: ['node_modules'],
root: path.join('.', 'build')
},
module: {
loaders: [
{ test: /\.css$/, loader: "style-loader!css-loader" },
{ test: /\.sass$/, loader: new ExtractTextPlugin.extract('css!sass') },
{ loader: 'ts', test: /\.ts$/, exclude: /(node_modules|bower_components)/ },
]
},
plugins: [
new ExtractTextPlugin('public/main.css', {allChunks: true})
]
};
I've tried both with the ExtractTextPlugin and without. But it just looks like webpack is ignoring both sass and css files all toghether. I've looked at probably a dozens of examples, but no matter how I configure webpack it doesn't pick up sass or css files.
Here's the package.json:
{
"name": "xxxxx",
"version": "0.0.0",
"private": true,
"dependencies": {
"async": "^1.5.0",
"cloudinary": "^1.2.4",
"css-loader": "^0.25.0",
"dotenv": "^2.0.0",
"express-handlebars": "^3.0.0",
"extract-text-webpack-plugin": "^1.0.1",
"handlebars": "^4.0.5",
"keystone": "^0.3.19",
"lodash": "^4.13.1",
"moment": "^2.10.6",
"node-sass": "^3.3.2",
"node-sass-middleware": "^0.9.7",
"sass-loader": "^4.0.2",
"style-loader": "^0.13.1",
"ts-loader": "^0.8.2",
"typescript": "^1.8.10",
"webpack": "^1.13.2",
"webpack-dev-middleware": "^1.8.1",
"webpack-hot-middleware": "^2.12.2"
},
"devDependencies": {
"eslint": "^2.12.0",
"eslint-config-keystone": "^2.3.1",
"eslint-plugin-react": "^5.1.1",
"typescript": "^1.8.10",
"typings": "^1.3.3"
},
"scripts": {
"lint": "eslint .",
"start": "node keystone.js"
}
}
Would appreciate if someone could shed some light about what's going on here.
I think I am right in saying that webpack builds up its bundle based on dependencies it finds in the code.
Do you require () your sass files anywhere?
(I would add this as a comment but I don't have that option yet)
Really Webpack is used to bundle the JavaScript and not the CSS/SASS. You need to add a task to handle your SASS files. Here's something to get you started:
var config = require('../config');
if(!config.tasks.css) return;
var gulp = require('gulp'),
gulpif = require('gulp-if'),
sass = require('gulp-sass'),
sourcemaps = require('gulp-sourcemaps'),
autoprefixer = require('gulp-autoprefixer'),
path = require('path'),
cssnano = require('gulp-cssnano');
var paths = {
src: path.join(config.root.src, config.tasks.css.src, '/**/*.{' + config.tasks.css.extensions + '}'),
dest: path.join(config.root.dest, config.tasks.css.dest)
}
var cssTask = function () {
return gulp.src(paths.src)
.pipe(gulpif(!global.production, sourcemaps.init()))
.pipe(sass(config.tasks.css.sass))
.pipe(autoprefixer(config.tasks.css.autoprefixer))
.pipe(gulpif(global.production, cssnano({autoprefixer: false})))
.pipe(gulpif(!global.production, sourcemaps.write()))
.pipe(gulp.dest(paths.dest));
}
gulp.task('css', cssTask)
module.exports = cssTask
Then just add that to your production build task.

Resources