aspnet / JavaScriptServices

[Archived] This repository has been archived
Apache License 2.0
3.03k stars 518 forks source link

DllReferencePlugin purpose in aspnet core spa app? #96

Closed asadsahi closed 8 years ago

asadsahi commented 8 years ago

No idea why this plugin is used in aspnetcore-spa apps inside webpack.config.js. Webpack documentation doesn't help either. Do we have to use this? what is manifest.json file? do we have to run the command (webpack --config config/webpack.config.vendor.js) to create it before running the asp.net core app?

new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require('../wwwroot/dist/vendor-manifest.json')
        })
laskoviymishka commented 8 years ago

Manifest json specify your third party dependencies. It specify what exact *.js files should be included in page from node_modules and how the mapped inside of our concatted file. Dependency described in webpack.config.vendor.js inside of vendor entry:

 entry: {
        vendor: [
            'bootstrap',
            'bootstrap/dist/css/bootstrap.css',
            'style-loader',
            'jquery',
            '@angular/common',
            '@angular/compiler',
            '@angular/core',
            '@angular/http',
            '@angular/platform-browser',
            '@angular/platform-browser-dynamic',
            '@angular/router-deprecated',
            '@angular/platform-server',
            '@angular/router-deprecated',
        ]
    },

In a fact you could use any configuration of your webpack (this one is just jump start suitable for most of projects). The only restriction for webpack config right now - you have to add entry with name 'main'.

asadsahi commented 8 years ago

Thanks @laskoviymishka

By default webpack knows how to load modules based on the dependencies, e.g if my entry file index.js references angular, it will load, bundle, minify, based on webpack configuration provided in webpack config file.

Still didn't get the benefit/purpose of webpack.config.vendor.js and manifest output from this configuration file. Also, do you know why the project uses DllReferencePlugin ?

laskoviymishka commented 8 years ago

@asadsahi well, you can remove it. Probably you right and this stuff could and should be removed. Right now we need to made some additional command before we could run ng2 app - webpack --config webpack.config.vendor.js if we remove this dll we probably remove this call also.

laskoviymishka commented 8 years ago

@asadsahi you are right, this is not really usefull here. It could be removed.

laskoviymishka commented 8 years ago

You could even remove webpack.config.vendor at all. In this case your webpack.config will be like:

var path = require('path');
var webpack = require('webpack');
var merge = require('extendify')({ isDeep: true, arrays: 'concat' });
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var extractCSS = new ExtractTextPlugin('styles.css');
var devConfig = require('./webpack.config.dev');
var prodConfig = require('./webpack.config.prod');
var isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Development';

module.exports = merge({
  resolve: {
    extensions: ['', '.js', '.ts']
  },
  module: {
    loaders: [
          { test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000' },
          { test: /\.ts$/, include: /ClientApp/, loader: 'ts-loader' },
          { test: /\.html$/, loader: 'raw-loader' },
          { test: /\.css/, loader: extractCSS.extract(['css']) }
    ]
  },
  entry: {
    main: ['./ClientApp/boot-client.ts']
  },
  output: {
    path: path.join(__dirname, 'wwwroot', 'dist'),
    filename: '[name].js',
    publicPath: '/dist/'
  },
  plugins: [
      new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
      new webpack.optimize.OccurenceOrderPlugin(),
      extractCSS
  ]
}, isDevelopment ? devConfig : prodConfig);

And don't forget to add bootstrap style into client boot:

import 'bootstrap';
import 'bootstrap/dist/css/bootstrap.css';

In this case everything will be bundled in single file.

asadsahi commented 8 years ago

Sweet and Simple :+1: , will give it a try in a bit and share my experiece as well.

xabikos commented 8 years ago

I also think that the webpack configuration right now is too complicated and certainly not easy to understand it. For development there is no point to split the bundles between vendor and rest. The most common approach is to create just a js file which contains everything. Then during preparation for production environment is better to split vendor dependencies with the app's own code. I am trying to create a sample for ReactRedux in ES6 and not in TypeScript and have to say that webpack configuration in hard to follow.

asadsahi commented 8 years ago

@laskoviymishka , works like a charm with no webpack.config.vendor.js

@xabikos Agree with you on webpack's configuration being complex in aspnetcore-spa generator. BTW, feeling sad after you mention that sample project you are working on is in ReactRedux in ES6 and not in Angular 2 & typescript :). I like your webpack middleware at somepoint, but I think aspnetcore-spa is converging the same idea of middleware into generator.

Right now I am currently working on a project template which is mix of:

1) aspnetcore-spa generator (for server side stuff) 2) Angular 2 webpack starter (I have picked some webpack stuff from this project, I like the way vendor/polyfills and application level providers and directives are organized in this this starter template, also, this project has lazy loading of bundles using es6-module loader with webpack, so that is inspiring too) 2) Angular 2 seed (Picked angular 2 styleguide following this project)

@SteveSanderson , Lets see if Steve likes the above ideas implemented in aspnetcore-spa (Angular 2 version) generator as well :)

Here is my webpack.config.js with no reference of jQuery or javascript element of bootstrap and sass loader:

var path = require('path');
var webpack = require('webpack');
var merge = require('extendify')({ isDeep: true, arrays: 'concat' });
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var extractCSS = new ExtractTextPlugin('styles.css');
var devConfig = require('./webpack.config.dev');
var prodConfig = require('./webpack.config.prod');
var isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Development';

module.exports = merge({
    resolve: {
        extensions: ['', '.js', '.ts']
    },
    module: {
        loaders: [
            { test: /\.ts$/, include: /Client/, loader: 'awesome-typescript-loader' },
            { test: /\.html$/, loader: 'raw-loader' },
            { test: /\.css/, loader: extractCSS.extract(['css']) },
            { test: /\.scss$/, loaders: ['raw-loader', 'sass-loader?sourceMap'] },
            { test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000' }
        ]
    },
    entry: {
        main: ['./Client/boot-client.ts']
    },
    output: {
        path: path.join(__dirname, '../wwwroot', 'dist'),
        filename: '[name].js',
        publicPath: '/dist/'
    },
    plugins: [
        new webpack.optimize.OccurenceOrderPlugin(),
        extractCSS
    ]
}, isDevelopment ? devConfig : prodConfig);
laskoviymishka commented 8 years ago

@asadsahi take my :+1:

Right now yo generator is really simple, and it still to much stuff to enhance. It may be great if there will be an option like one which we use in react and react-redux. IMHO angular2-seed and Angular 2 webpack starter looks really scary and for some case it overkill. But sometimes it really best starters (especially webpack version i used it for prod app).

xabikos commented 8 years ago

@asadsahi I am not into both Angular or TypeScript and there is already a template for Angular 2 in TypeScript. Now about the middleware I have created here indeed is simpler and spa services provide way more functionality. My goal is to just make the usage of webpack as module bundler really easy in any asp.net core application. Even if we don't use React or Angular.

I really like this project and effort of having server side rendering of JavaScript apps but in order to succeed I think a template in ES6 should be present for sure. In general TypeScript is not a very popular choice in React community and it's a pity not to have an option for pure JavaScript devs.

asadsahi commented 8 years ago

@laskoviymishka agree with angular 2 seed and webpack angular 2 starter being complex beasts and I have had few iterations in last week to somehow get most of the functionality working in aspnetcore-spa template from those projects, but trust me you don't want to waste time like me. Thiking about 80/20 rule in webpack world, we may not need alot of customisations. Therefore, I am picking the better parts from those two projects only.

@xabikos it makes sense. Different tooling in different situations. :)

SteveSandersonMS commented 8 years ago

The reason for the "vendor" bundle (and the DllReferencePlugin which enables it) is just to make your builds much faster. All the really huge dependencies (e.g., Angular, in your case) only need to go through Webpack's static analysis process when you explicitly rebuild your "vendor" module, and can be skipped entirely for most builds.

In practice I find this shortens the build time from about 15 seconds to about 3 seconds. This is especially important when you're using Hot Module Replacement, because you want your code changes to appear in the browser pretty much instantly, not 10 seconds after you make them.

I appreciate that it makes the webpack setup more complex, but the benefit is pretty huge. If anyone has suggestions for a simpler webpack setup that retains such fast builds, please let me know!

Please reopen if you think this explanation is inadequate or there's a better solution!

asadsahi commented 8 years ago

That perfectly explains it @SteveSandersonMS .

Reason is strong and I am in favour of keeping it.

Thanks