Huge number of files generated for every Angular project - javascript

I wanted to start a simple hello world app for Angular.
When I followed the instructions in the official quickstart the installation created 32,000 files in my project.
I figured this is some mistake or I missed something, so I decided to use angular-cli, but after setting up the project I counted 41,000 files.
Where did I go wrong? Am I missing something really really obvious?

There is nothing wrong with your configuration.
Angular (since version 2.0) uses npm modules and dependencies for development. That's the sole reason you are seeing such a huge number of files.
A basic setup of Angular contains transpiler, typings dependencies which are essential for development purposes only.
Once you are done with development, all you will need to do is to bundle this application.
After bundling your application, there will be only one bundle.js file which you can then deploy on your server.
'transpiler' is just a compiler, thanks #omninonsense for adding that.

Typical Angular2 Project
NPM Package Files (Development) Real World Files (Deployment)
#angular 3,236 1
rxJS 1,349 1*
core-js 1,341 2
typings 1,488 0
gulp 1,218 0
gulp-typescript 1,243 0
lite-server 5,654 0
systemjs-builder 6,470 0
__________________________________________________________________
Total 21,999 3
*: bundled with #angular
[ see this for bundling process ⇗ ]

There is nothing wrong with your development configuration.
Something wrong with your production configuration.
When you develop a "Angular 2 Project" or "Any Project Which is based on JS" you can use all files, you can try all files, you can import all files. But if you want to serve this project you need to COMBINE all structured files and get rid of useless files.
There are a lot of options for combine these files together:
YUI Compressor
Google Closure Compiler
For server side (I think it is best) GULP

As several people already mentioned: All files in your node_modules directory (NPM location for packages) are part of your project dependencies (So-called direct dependencies). As an addition to that, your dependencies can also have their own dependencies and so on, etc. (So-called transitive dependencies). Several ten thousand files are nothing special.
Because you are only allowed to upload 10'000 files (See comments), I would go with a bundler engine. This engine will bundle all your JavaScript, CSS, HTML, etc. and create a single bundle (or more if you specify them). Your index.html will load this bundle and that's it.
I am a fan of webpack, so my webpack solution will create an application bundle and a vendor bundle (For the full working application see here https://github.com/swaechter/project-collection/tree/master/web-angular2-example):
index.html
<!DOCTYPE html>
<html>
<head>
<base href="/">
<title>Webcms</title>
</head>
<body>
<webcms-application>Applikation wird geladen, bitte warten...</webcms-application>
<script type="text/javascript" src="vendor.bundle.js"></script>
<script type="text/javascript" src="main.bundle.js"></script>
</body>
</html>
webpack.config.js
var webpack = require("webpack");
var path = require('path');
var ProvidePlugin = require('webpack/lib/ProvidePlugin');
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
var UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
/*
* Configuration
*/
module.exports = {
devtool: 'source-map',
debug: true,
entry: {
'main': './app/main.ts'
},
// Bundle configuration
output: {
path: root('dist'),
filename: '[name].bundle.js',
sourceMapFilename: '[name].map',
chunkFilename: '[id].chunk.js'
},
// Include configuration
resolve: {
extensions: ['', '.ts', '.js', '.css', '.html']
},
// Module configuration
module: {
preLoaders: [
// Lint all TypeScript files
{test: /\.ts$/, loader: 'tslint-loader'}
],
loaders: [
// Include all TypeScript files
{test: /\.ts$/, loader: 'ts-loader'},
// Include all HTML files
{test: /\.html$/, loader: 'raw-loader'},
// Include all CSS files
{test: /\.css$/, loader: 'raw-loader'},
]
},
// Plugin configuration
plugins: [
// Bundle all third party libraries
new CommonsChunkPlugin({name: 'vendor', filename: 'vendor.bundle.js', minChunks: Infinity}),
// Uglify all bundles
new UglifyJsPlugin({compress: {warnings: false}}),
],
// Linter configuration
tslint: {
emitErrors: false,
failOnHint: false
}
};
// Helper functions
function root(args) {
args = Array.prototype.slice.call(arguments, 0);
return path.join.apply(path, [__dirname].concat(args));
}
Advantages:
Full build line (TS linting, compiling, minification, etc.)
3 files for deployment --> Only a few Http requests
Disadvantages:
Higher build time
Not the best solution for Http 2 projects (See disclaimer)
Disclaimer: This is a good solution for Http 1.*, because it minimizes the overhead for each Http request. You only have a request for your index.html and each bundle - but not for 100 - 200 files. At the moment, this is the way to go.
Http 2, on the other hand, tries to minimize the Http overhead, so it's based on a stream protocol. This stream is able to communicate in both direction (Client <--> Server) and as a reason of that, a more intelligent resource loading is possible (You only load the required files). The stream eliminates much of the Http overhead (Less Http round trips).
But it's the same as with IPv6: It will take a few years until people will really use Http 2

You need to ensure that you're just deploying the dist (short for distributable) folder from your project generated by the Angular CLI. This allows the tool to take your source code and it's dependencies and only give you what you need in order to run your application.
That being said there is/was an issue with the Angular CLI in regards to production builds via `ng build --prod
Yesterday (August 2, 2016) a release was done which switched the build mechanism from broccoli + systemjs to webpack which successfully handles production builds.
Based upon these steps:
ng new test-project
ng build --prod
I am seeing a dist folder size of 1.1 MB across the 14 files listed here:
./app/index.js
./app/size-check.component.css
./app/size-check.component.html
./favicon.ico
./index.html
./main.js
./system-config.js
./tsconfig.json
./vendor/es6-shim/es6-shim.js
./vendor/reflect-metadata/Reflect.js
./vendor/systemjs/dist/system.src.js
./vendor/zone.js/dist/zone.js
Note Currently to install the webpack version of the angular cli, you must run... npm install angular-cli#webpack -g

Creating a new project with angular cli recently and the node_modules folder was 270 mb, so yes this is normal but I'm sure most new devs to the angular world question this and is valid. For a simple new project it would make sense to pare the dependencies down maybe a bit;) Not knowing what all the packages depend on can be a bit unnerving especially to new devs trying the cli out for the first time. Add to the fact most basic tutorials don't discuss the deployment settings to get the exported files only needed. I don't believe even the tutorial offered on the angular official website talks about how to deploy the simple project.

Angular itself has lots of dependencies, and the beta version of CLI downloads four times more files.
This is how to create a simple project will less files ("only" 10K files)
https://yakovfain.com/2016/05/06/starting-an-angular-2-rc-1-project/

Seems like nobody have mentioned Ahead-of-Time Compilation as described here: https://angular.io/docs/ts/latest/cookbook/aot-compiler.html
My experience with Angular so far is that AoT creates the smallest builds with almost no loading time. And most important as the question here is about - you only need to ship a few files to production.
This seems to be because the Angular compiler will not be shipped with the production builds as the templates are compiled "Ahead of Time". It's also very cool to see your HTML template markup transformed to javascript instructions that would be very hard to reverse engineer into the original HTML.
I've made a simple video where I demonstrate download size, number of files etc. for an Angular app in dev vs AoT build - which you can see here:
https://youtu.be/ZoZDCgQwnmQ
You'll find the source code for the demo here:
https://github.com/fintechneo/angular2-templates
And - as all the others said here - there's nothing wrong when there are many files in your development environment. That's how it is with all the dependencies that comes with Angular, and many other modern frameworks. But the difference here is that when shipping to production you should be able to pack it into a few files. Also you don't want all of these dependency files in your git repository.

This is actually not Angular specific, it happens with almost any project that uses the NodeJs / npm ecosystem for its tooling.
Those project are inside your node_modules folders, and are the transititve dependencies that your direct dependencies need to run.
In the node ecosystem modules are usually small, meaning that instead of developing things ourselves we tend to import most of what we need under the form of a module. This can include such small things like the famous left-pad function, why write it ourselves if not as an exercise ?
So having a lot of files its actually a good thing, it means everything is very modular and module authors frequently reused other modules. This ease of modularity is probably one of the main reasons why the node ecosystem grew so fast.
In principle this should not cause any issue, but it seems you run into a google app engine file count limit. In that I case I suggest to not upload node_modules to app engine.
instead build the application locally and upload to google app engine only the bundled filesn but don't to the build in app engine itself.

If you are using angular cli's newer version use ng build --prod
It will create dist folder which have less files and speed of project will increased.
Also for testing in local with best performance of angular cli you can use ng serve --prod

if you use Angular CLI you can always use --minimal flag when you create a project
ng new name --minimal
I've just run it with the flag and it creates 24 600 files and ng build --prod produces 212 KB dist folder
So if you don't need water fountains in your project or just want to quickly test something out this I think is pretty useful

If your file system supports symbolic links, then you can at least relegate all of these files to a hidden folder -- so that a smart tool like tree won't display them by default.
mv node_modules .blergyblerp && ln -s .blergyblerp node_modules
Using a hidden folder for this may also encourage the understanding that these are build-related intermediate files that don't need to be saved to revision control -- or used directly in your deployment.

There is nothing wrong. These are all the node dependencies that you have mentioned in the package.json.
Just be careful if you have download some of the git hub project, it might have lot of other dependencies that are not actually require for angular 2 first hello world app :)
make sure you have angular dependencies
-rxjs
-gulp
-typescript
-tslint
-docker

There is nothing wrong with your development configuration.
if you use Angular CLI you can always use --minimal flag when you create a project
ng new name --minimal

Related

How can Babel be used without bundler, but with a dev-experience similar to webpack?

I'm trying to build a new project with ES6 modules without bundling. I still want to use babel-7 to translate TypeScript and JSX to JS. I find it hard to figure out how to set up a development-server for it. I couldn't find any kind of "babel-dev-server" that works similar to webpack-dev-server (hot-module-reloading, browser-sync, file-watcher).
One possibility would be to use browser sync as a static server on e.g. dist and run something like babel src --out-dir dist --watch in parallel. But this excludes hot-reloading and seems a bit clumsy to me. Besides, it would still be useful for build- and dev-steps if you could give the JS-files a hash to control caching better. Or can I configure a build-tool like webpack so that it doesn't perform bundling but still performs some transformations (like putting the hashs in the filenames in imports)?
Prototyping way
A very simple way to do this is to see the server and the transpiling as separate steps
You could use a standalone version of babel as the first script that you load, so you can write jsx inside your html document of javascript files without compiling them.
Simply add on of the cdn links from https://cdnjs.com/libraries/babel-standalone/ as a script like so:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
<script src="/your/jsx/here.js"></script>
<script>
// or here
</script>
</head>
<body>
<div id="application" />
<noscript>This app needs javascript enabled in order to run.</noscript>
</body>
</html>
This would allow you to really quickly prototype things using any webserver that watches files. You can do this using any task runner plugin (i.e. for grunt or gulp) or if you are using visual studio have a look at LiveServer plugin.
When you are moving to production grade you might not want to include the entire babel library. See the other two approaches.
Webpack way
You're asking how to use webpack without bundling. Which can be done using file loader plugin to load every file separately, using a glob pattern. Do make sure whether this is indeed what you need. If all you want is to simply debug your code an relate it back to the original file after compiling, all you need is a standard webpack configuration using bundling and sourcemaps.
Taskrunner way
One way to have even more control over how each file is processed, you can use a taskrunner to do the compile step for you. Below is a simplified example configuration for taskrunner https://gulpjs.com/.
gulpfile.js
const gulp = require('gulp');
const watch = require('gulp-watch');
const webpackStream = require('webpack-stream');
const webpack = require('webpack');
const eslint = require('gulp-eslint');
gulp.task('watch', function() {
return watch('src/**.js', ['compile']);
});
gulp.task('lint', function() {
return gulp.src(['src/*.js', 'src/*/*.js'])
.pipe(eslint({
parser: 'babel-eslint',
parserOptions: {
ecmaFeatures: {
jsx: true
},
sourceType: 'module'
}
}))
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
gulp.task('compile', ['lint'], function() {
return gulp.src('src/main.js')
.pipe(webpackStream({
output: {
filename: 'main.js',
libraryTarget: 'commonjs2',
sourceMapFilename: 'main.js.map',
},
plugins: [],
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: [
require.resolve('babel-preset-es2015'),
require.resolve('babel-preset-stage-0'),
],
},
},
],
},
}), webpack)
.pipe(gulp.dest('dist/'));
});
This example file can be run, using gulp watch. It'll watch the files for a chance and when it does trigger the other tasks.
I only had an example with webpack, but you can replace it by any other compiler component or even write your own compile step if you want (probably you don't).
This way you have exact control over every step your files go through. Most of which (and more) can also be achieved using the Webpack way. However, it would have the downside of inserting all its boilerplate on top of each processed file, when processing each file as a separate bundle. Ultimately probably something could be done with common chunks plugin.
With the latest release of Snowpack (formerly #pika/web) this should be possible now!
From their website:
TL;DR - With Snowpack you can build modern web apps (using React, Vue, etc.) without a bundler (like Webpack, Parcel, Rollup). No more waiting for your bundler to rebuild your site every time you hit save. Instead, every change is reflected in the browser instantly.
And their "How it Works":
Instead of bundling on every change, just run Snowpack once right after npm install.
Snowpack re-installs your dependencies as single JS files to a new web_modules/ directory. It never touches your source code.
Write code, import those dependencies via an ESM import, and then run it all in the browser.
Skip the bundle step and see your changes reflected in the browser immediately after hitting save.
Keep using your favorite web frameworks and build tools! Babel & TypeScript supported.
check https://www.snowpack.dev/ for more information, they have done a great job with their documentation, it looks really promising!
With webpack and source maps, it shouldn't matter that it changes your code. While this can be a challenge to set up initially, once you get it working you can look at your original source code in the browser debugging tools exactly as they appear to you on disk. The VS Code editor also does a good job of supporting this feature, allowing you to set breakpoints and look at the values of variables directly in your editor without having to use the browser developer tools.
However, if you are still set on trying to get this to work with your original source files then you are right that your ES6 code should just work in most modern browsers
For live reload you could check out the npm livereload package.
Or you could roll your own and figure out how webpack-dev-server does it. They use the chokidar npm package to watch the file system for changes and then they notify the broswer via web sockets. You could probably throw something together that's similar with a little effort.
Here is how webpack-dev-server initiates it:
const watcher = chokidar.watch(watchPath, options);
watcher.on('change', () => {
this.sockWrite(this.sockets, 'content-changed');
});
Obviously there is some JavaScript that runs in the browser waiting on a websocket for that message.
You could use a Webpack plugin like Emit All.

How to put Vue.js in production mode using webpack 2.7?

I've got an existing code base in which Vue.js has performance problems. I also see this notice in the browser console:
so I guess an easy fix could be to put Vue into production mode.
In the suggested link I try to follow the instructions for webpack. We're on Webpack version 2.7 (current stable version is 4.20). In the instructions it says that in Webpack 3 and earlier, you’ll need to use DefinePlugin:
var webpack = require('webpack')
module.exports = {
// ...
plugins: [
// ...
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
}
So in my package.json I've got a build script defined:
To build for production I run yarn run build and it runs a build.js file (paste here) which in turn calls webpack.base.conf.js (paste here) and webpack.prod.conf.js (paste here).
As you can see in the paste I use the DefinePlugin as suggested by the docs.
I also found a file called vue-loader.conf.js (paste here) and to be sure I also added the DefinePlugin in there as well.
I can run yarn run build which ends without errors, but when serve the site over Apache and open the browser it still shows the notification that we're in development mode.
To be sure it actually uses the files created by webpack I completely removed the folder /public/webpack/ and checked that the webinterface didn't load correctly without the missing files and then built again to see if it loaded correctly after the command finished. So it does actually use the files built by this webpack process. But Vue is actually not created in production mode.
What am I doing wrong here?
The problem may be in your 'webpack.base.conf.js' as i suspected, thank you for sharing it, upon searching i've found an issue resolving your 'production not being detected' problem on github here
The solution requires that you change 'vue$': 'vue/dist/vue' to 'vue$': vue/dist/vue.min in production.
You will find the original answer as:
#ozee31 This alias 'vue$': 'vue/dist/vue' cause the problem, use vue/dist/vue.min in production environment.

How can we integrate Vue JS with ASP.NET MVC and nuget packages

How can we integrate Vue JS with MVC Project that is existing and using with Nuget Package.
Tried with below approach.
<h3>VueJS 2 in ASP.NET MVC 5</h3>
<div id="aboutPage">
{ { message }}
</div>
<script>
var aboutPage = new Vue({
el: '#aboutPage',
data: {
message: 'Hello Vue! in About Page'
}
});
</script>
Question:
Is there need for any additional package like - webpack or gulp, we already have bundle config of MVC?
2.
How can we create separate files or design for each view like:
To separate the service call (to call web api from client side)
separate out the template file.
methods or logic to write in JS.
any example for MVC with VueJS like - controller, view,service, vue JS file is great..
Thanks a lot !
You can use vuejs buy adding it to your layout.
#Scripts.Render("~/node_modules/vue/dist/vue.min.js")
You need to install Nodejs on your machine to use NPM and ES6 features.
For integrate Vue.js in .NET MVC you need module bundler (webpack, gulp),can choose one of this options, the popular is webpack:
1:(Gulp, Browserify), which has some limitations such as supporting only require syntax handling assets. and the setup is kind of complicated.
2:(Webpack), which has a lot of cool things you can do with it, Hot Reload. check this repo
by using webpack, you config it to handle just js files and it will handle js files for build too , upon build each entry will be copied inside Scripts/bundle, also you need some loaders such ass (vue, scss, css and js) for webpack. check this
Webpack uses webpack-dev-server for development which is basically a node.js based server which serves assets (javascript, css etc) that our browsers can interpret. Usually these assets include some development friendly features like Hot Reload. These assets are not minified and are quite different from the ones generated when building for production.
devServer: {
proxy: {
'*': {
target: 'http://localhost:5001',
changeOrigin: true
}
}
},
webpack-dev-server has a feature which can proxy requests from one url to another. In this case, every request from "webpack dev server " will be proxied to your "asp.mvc server". So, if we run our MVC app on http://localhost:5001 and run npm run dev , on port 8086 you should see the same output as from our MVC app.
Answers:
1: yes you have to setup Webpack or Gulp.
2. by using webpack you can all thing for file structuer that you want
check this tree
-app
--libs
----utils
----components
---------commons
---------.......
-----pages
---------.....
check this articles
https://medium.com/corebuild-software/vue-js-and-net-mvc-b5cede228626
http://www.lambdatwist.com/dot-net-vuejs/
If you want to keep the .cshtml files and use MVC as a multipage application, you can take a look at this template as an example or starting point. https://github.com/danijelh/aspnetcore-vue-typescript-template
You can create modules of pages which you want to enhance with Vue and import that bundle.

Is there a way I can change any of the files shown here to deploy with webpack?

What's coming? (1) Short background. (2) Question. (3) Detail (short; file listings just long enough to show relevant information). (4) Question again.
Short background: I want to deploy my web site using webpack. webpack is looking for style-loader and css-loader in the wrong directories, so my builds aren't completing.
Question
Is there a way I can change any of the files shown here to deploy with webpack?
Detail
environment
Windows 10 Home -64, up-to-date/ Toshiba Satellite with AMD A6
Node v6.2.0/ webpack v1.13.2
relevant files and directory structure
C:\Dev\example\example.js
C:\Dev\example\bluebird.js
C:\Dev\example\jquery.js
C:\Dev\example\img\image1.jpg
C:\Dev\example\img\image2.jpg
C:\Dev\example\img\svg1.svg
C:\Dev\example\built\package.json
C:\Dev\example\built\webpack.config.js
C:\Dev\example\built\index1.html
C:\Dev\example\built\index2.html
C:\Dev\example\built\example.bundle.js
C:\Dev\example\built\[hash1].jpg
C:\Dev\example\built\[hash2].jpg
C:\Dev\example\built\[hash3].svg
C:\Dev\node-modules\webpack
C:\Dev\node-modules\css-loader
C:\Dev\node-modules\file-loader
C:\Dev\node-modules\html-loader
C:\Dev\node-modules\style-loader
C:\Dev\node-modules\uglify-js
C:\Dev\node-modules\url-loader
C:\Dev\example\built\package.json
{
"name": "example",
"version": "0.0.1",
"description": "example",
"main": "example.bundle.js",
"author": "Bald Eagle"
}
call to webpack: I call webpack at the command prompt from C:\Dev\example\built with one line (two here for your convenience)
node C:\Dev\node_modules\webpack\bin\webpack.js -p --display-reasons
--display-error-details --display-modules --profile
C:\Dev\example\built\webpack.config.js
"use strict"
let path = require("path")
let webpack = require("webpack")
let preferEntry = true // for OccurrenceOrderPlugin
module.exports = {
context: "C:/Dev/example/built",
entry: [
"./index1.html",
"./../jquery.js",
"./../bluebird.js",
"./../example.css"
],
output: {
path: "C:/Dev/example/built",
filename: "./example.bundle.js",
publicPath: "http://www.example.com"
},
module: {
loaders: [
{
test: /\.(?:gif|jpg|jpeg|svg)$/,
loader: "file!url"
},
{
test: /\.html$/,
loader: "html"
},
{
test: /\.png$/,
loader: "url-loader?mimetype=image/png"
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
} ],
plugins: [
new webpack.optimize.UglifyJsPlugin({minimize: true}),
new webpack.ProvidePlugin({
'window.jQuery': 'jquery',
'window.$': 'jquery',
}) ] },
resolve: {
root: path.resolve("./index1.html"),
modulesDirectories: ["node_modules", "built"],
fallback: "C:/Dev"
},
resolveLoader: {
fallback: "C:/Dev",
modulesDirectories: ["node_modules"]
}
}
C:\Dev\example\built\index1.html: My goal for this HTML file is to point webpack the right direction to collect all information for the web site into its example.bundle.js file. I shortened one long line (clip) and excluded irrelevant lines, including the entire body.
<!doctype html>
<html>
<head>
<script src="./../example.js"></script>
<link href="./../example.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css? (clip) type="text/css" />
<script src="./../jquery.js"></script>
<script src="./../bluebird.js"></script>
</head>
<body>
</body>
</html>
feedback from webpack
It outputs routine information about building pieces of example.bundle.js (represented with ...), except these: (I added any double asterisks **; I broke some long lines and indented the later parts of such lines.)
...
[9] ./../example.css 919 bytes {0} [built] [**2 errors**]
single entry ./../example.css [0] multi main
WARNING in ./example.bundle.js from UglifyJs
...
Condition always false [C:/Dev/~/style-loader!
C:/Dev/~/css-loader!**./../example.css:10,0**]
Dropping unreachable code [C:/Dev/~/style-loader!
C:/Dev/~/css-loader!**./../example.css:12,0**]
Side effects in initialization of unused variable update
[C:/Dev/~/style-loader!C:/Dev/~/css-loader!
**./../example.css:7,0**]
**ERROR** in ./../example.css
Module not found: Error: Cannot resolve 'file' or 'directory'
./../node_modules/css-loader/index.js in
C:/Dev/example/built\..
resolve file
**C:/Dev/example/built\node_modules\css-loader\index.js
doesn't exist**
[plus more similarly inaccurate variants; it should be looking
for C:\Dev\node_modules\css-loader\index.js; it's there]
...
**ERROR** in ./../example.css
Module not found: Error: Cannot resolve 'file' or 'directory'
./../node_modules/style-loader/addStyles.js in
C:/Dev/example/built\..
resolve file
**C:/Dev/example/built\node_modules\style-loader\addStyles.js.webpack.js
doesn't exist**
[plus more similarly inaccurate variants]
...
With the double asterisks, I wanted to highlight that webpack outputted that there'd be two errors and outputted the two errors. Also, I wanted to highlight the cited points of error in css. Those lines are below.
C:\Dev\example\example.css: I show only the first twelve lines because of the lines webpack cited as errors; I added line numbers.
1 /* example web site
2 * blah
3 * blah
4 * blah
5 * blah
6 * blah
7 *
8 * Version
9 */
10
11 /* defaults */
12 body, div {
My conclusion: The points webpack cited are not points of error. Maybe the points cited apply to a minified version of the file. Or to some code.
Problem when I point a browser to index1.html above: All content and rendering are fine; JavaScript isn't enabled. (Consistent with not processing css correctly?)
C:\Dev\example\built\index2.html: My goal for this HTML file is to use the same webpack techniques I'll use in the index.html that will be on the web server. I changed this the same ways I changed index1.html.
<!doctype html>
<html>
<head>
<script src="./example.bundle.js"></script>
<link href="https://fonts.googleapis.com/css? (clip) type="text/css" />
</head>
<body>
</body>
</html>
Problem when I point a browser to index2.html immediately above: All content shows (including the three images), but (1) JavaScript isn't enabled and (2) there's no effect from css (no colors or positioning, etc.) (Consistent with not processing css correctly?)
Question
Is there a way I can change any of the files shown here to deploy with webpack?
Thanks for taking the time to read. Thanks in advance for any responses.
Need more detail? I'll provide it if I can.
It seems like you've set up your project in a very unusual style for Node.js development which makes your setup more complicated than it needs to be. I'm not sure if that is a hard requirement, but since you've not mentioned it to be required, I'm assuming you are allowed to change your directory structure.
Use local dependencies
In Node.js, all dependencies are installed separately for each project. It enables you to use different versions of a dependency while working on different projects without the need to switch these dependencies manually. You should put the package.json in the root folder of your project (I assume C:\Dev\example in your case) and then run npm install webpack css-loader style-loader --save-dev. NPM is the package manager for Node.js that comes pre-bundled with the executable so it should already be installed on your system. After running npm install you should see a node_modules folder which contains all these project-specific dependencies. You should not commit these dependencies to your version control system because they may contain platform-specific binaries that are not usable on different machines. Every developer in this project needs to run npm install first.
Configure your common commands under scripts
NPM provides the possibility to add common commands as scripts to your package.json. This way, other developers (including "Future You") only need to remember npm run some-script instead of all the command-line options. One little known feature of NPM is, that it prepends ./node_modules/.bin to your $PATH on runtime which means that inside scripts you can reference any executable installed in your local node_modules just as if it was installed globally. Thus you only need to write:
"scripts": {
"start": "webpack --config ./path/to/webpack.config.js"
}
and it will use your local webpack installation. As a side-note: It's best-practice to provide a "start" script. It can be called by just running npm start.
Your webpack config
Your webpack config looks ok, but I have some advice:
You should separate between your development stuff and the actual build. Usually, the webpack.config.js is placed in the root of your project because then you just need to run webpack and webpack will look for a config in the current directory. Then, you should have a src or app folder which contains all the development files, including the index HTML files as you've mentioned. At last, you create a build folder which is completely wiped before a build. This way, your build does not contain any obsolete files.
Do not use absolute paths in your webpack.config. It makes sharing your project a lot harder – including "Future You" that moves the project to another directory. Use the Node.js builtin path module and the special module variable __dirname to resolve absolute paths. You can also use require.resolve to use Node's resolving algorithm.
Do not set the context and the publicPath option unless you know what you are doing. Given from the information you've provided, I doubt that these options are necessary here.
Since you've installed all the dependencies locally, you should remove all the resolving options because it should work out-of-the-box now.
Although it is permitted, you should not omit the -loader postfix in your loader configurations. It can lead to hard-to-understand errors when you have a css or html module in your node_modules just by coincidence.
The problem with index.html files
webpack is a JavaScript bundler. That's why you need to have a css- or an html-loader if you want to include HTML or CSS. These loaders transform HTML or CSS into a JavaScript module by transforming the text contents into strings that are exported. This has some nice advantages like hot module replacement or CSS modules. But it also means that you can't use an HTML or CSS file as the only entry point to your website. Every HTML and CSS will eventually be translated to JavaScript. This trade-off is ok for single-page applications where you need JS anyway, but it is probably surprising for everyone who tries to use webpack on a static site.
Since you're not the first one with this problem, several solutions have already emerged. My recommendation is to use the HTML Webpack Plugin in combination with the Extract Text Webpack Plugin.
The Extract Text Webpack Plugin can be used to extract static JS strings out of the bundle into a speparate file. This is exactly what you need to remove CSS from the JS bundle.
The HTML Webpack Plugin creates an index HTML file that includes all the generated JS and CSS files. Out of the box, it will just generate an HTML file with no contents (often referred to application shell which is typical for single-page applications). Since you already have content in your index HTML files, you need to configure your HTML files as templates. You'll need to add a plugin for each HTML file.
These plugins work pretty well, but this setup is already pretty complex. You should decide if you want to use webpack just for JS or also for HTML and CSS.

Working project structure that uses grunt.js to combine JavaScript files using RequireJS?

I have some projects that use RequireJS to load individual JavaScript modules in the browser, but I haven't optimized them yet. In both development and production, the app makes a separate request for each JavaScript file, and now I would like to fix that using Grunt.
I have tried to put together a simple project structure to no avail, so I'm wondering if someone can provide a working example for me. My goals are the following:
In development mode, everything works in the browser by issuing a separate request for each required module. No grunt tasks or concatenation are required in development mode.
When I'm ready, I can run a grunt task to optimize (combine) all of the JavaScript files using r.js and test that out locally. Once I'm convinced the optimized application runs correctly, I can deploy it.
Here's a sample structure for the sake of this conversation:
grunt-requirejs-example/
grunt.js
main.js (application entry point)
index.html (references main.js)
lib/ (stuff that main.js depends on)
a.js
b.js
requirejs/
require.js
text.js
build/ (optimized app goes here)
node_modules/ (necessary grunt tasks live here)
Specifically, I'm looking for a working project structure that I can start from. My main questions are:
If this project structure is flawed, what do you recommend?
What exactly needs to be in my grunt.js file, especially to get the r.js optimizer working?
If all of this isn't worth the work and there's a way to use the grunt watch task to automatically build everything in development mode every time I save a file, then I'm all ears. I want to avoid anything that slows down the loop from making a change to seeing it in the browser.
I use the grunt-contrib-requirejs task to build project based on require.js. Install it inside your project directory with:
npm install grunt-contrib-requirejs --save-dev
BTW: --save-dev will add the package to your development dependencies in your package.json. If you're not using a package.json in your project, ignore it.
Load the task in your grunt file with:
grunt.loadNpmTasks('grunt-contrib-requirejs');
And add the configuration to your grunt.initConfig
requirejs: {
production: {
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js",
out: "path/to/optimized.js"
}
}
}
Now you're able to build your require.js stuff into a single file that will be minimized with uglifyjs by running grunt requirejs
You can bundle a set of different tasks into some sort of main task, by adding this to your grunt file
grunt.registerTask('default', ['lint', 'requirejs']);
With this, you can simply type grunt and grunt will automatically run the default task with the two 'subtasks': lint and requirejs.
If you need a special production task: define it like the above
grunt.registerTask('production', ['lint', 'requirejs', 'less', 'copy']);
and run it with
grunt production
If you need different behaviors for 'production' and 'development' inside i.e. the requirejs task, you can use so called targets. In the configuration example above it's already defined as production. You can add another target if you need (BTW, you can define a global config for all targets by adding a options object on the same level)
requirejs: {
// global config
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js"
},
production: {
// overwrites the default config above
options: {
out: "path/to/production.js"
}
},
development: {
// overwrites the default config above
options: {
out: "path/to/development.js",
optimize: none // no minification
}
}
}
Now you can run them both at the same time with grunt requirejs or individually with grunt requirejs:production, or you define them in the different tasks with:
grunt.registerTask('production', ['lint', 'requirejs:production']);
grunt.registerTask('development', ['lint', 'requirejs:development']);
Now to answer your questions:
I would definitely use a subfolder in your project. In my case I use a 'src' folder for development that is build into a 'htdocs' folder for production. The project layout I prefere is:
project/
src/
js/
libs/
jquery.js
...
appname/
a.js
b.js
...
main.js // require.js starter
index.html
...
build/
... //some tmp folder for the build process
htdocs/
... // production build
node_modules/
...
.gitignore
grunt.js
package.json
see above
You can do so, but I wouldn't recommend to add requirejs to the watch task, it's a resource hungry task and it will slow down your machine noticeable.
Last but not least: Be very cautious when playing around with r.js. Especially when you want to optimize the whole project with r.js by adding a modules directive to your config. R.js will delete the output directory without asking. If it happens that it is accidentally configured to be your system root, r.js will erase your HDD. Be warned, I erased my whole htdocs folder permanently some time ago while setting up my grunt task... Always add keepBuildDir:true to your options when playing around with the r.js config.

Categories