How to embed dependencies using urequire - javascript

I use grunt-urequire plugin to compile my project-1's modules into single file (let's call it project-1.js). Config looks like this:
urequire: {
umd: {
template: 'UMD',
path: 'src',
dstPath: 'dist/umd'
},
dev: {
template: 'combined',
path: 'src',
main: 'Main',
dstPath: 'dist/<%= pkg.name %>-<%= pkg.version %>.js'
},
min: {
derive: ['dev', '_defaults'],
dstPath: 'dist/<%= pkg.name %>-<%= pkg.version %>.min.js',
optimize: 'uglify2'
},
_defaults: {
useStrict: true,
noConflict: true,
bundle: {
dependencies: {
exports: {
root: {
'Main': 'Project1'
}
}
}
}
}
}
Project-1 depends on project-2 which is also managed by grunt-urequire. In package.json:
"devDependencies": {
"project2": "^0.1",
...
}
Now I want to embed project-2 dependency into project-1 on build so that one could just do
<script src="project-1.js"></script>
in browser and don't include project-2 manually.
I know browserify supports this, but can I do it using urequire?

uRequire doesn't embed external dependencies (like jquery, underscore etc) into the combined.js file, unlike browserify which is the only option (as far as I know) and its also the default behavior of r.js.
This is partly intentional, cause its better to load (either using RequireJS or <script/>) these external libraries from a CDN: your user's browser might have already cached them last time it loaded your app (or someone else's app). And next time your myApp.js changes, it will download only that and not a monolithic bundle that contains all the same external libs all over again.
uRequire actually goes a long way to make sure these are loaded externally, whether on nodejs (using plain node's require) or the browser, using AMD or the exported global properties (like window.$, window._ or whatever the external library is mapped to).
I would imagine you can easily override this behavior: just place project-2.js whenever you build it onto the source folder of project-1, and just use it in project-1 as a normal dependency.
Alternatively you can again build/convert all project-2 files as AMD (not combined) into the source folder of project-1 and use them as being part of it.
Finally, you could just symlink the project-2 source into project-1, its supported on unix/linux for decades and also on Windows 7 onwards. Then uRequire will convert the sources from both projects only once and build as a single output.
Ideally I would like to have virtual sources (see https://github.com/anodynos/uRequire/issues/40) so you can leave both projects separate (i.e not build one into the other), but build both as one output.

If you want to version the 2 projects on the same git repository because they are updated together and have the same release lifecycle, you can have a build script in 2 parts:
First part is to compile project2 (project2/src)
Second part is to compile project1 (project1/src)
During the compilation of project2, you can copy the distributed JS of project2 into project1/src so that it is automatically.
If you have different release lifecycles, you can use some grunt tool to download the dependency from a CDN / NPM and put it into the project1/src folder before packaging project 1
This is somehow what is done by Browserify by using NPM, but it would probably be the same with Bower, components or custom JS code to download the dependencies. I would recommend using a tool like NPM however because it also download transitive dependencies (if one day project2 introduces a dependency, you won't have to touch project1 build...)
Finally, I don't know uRequire but maybe you could be inspired by this project, which embeds dependencies in the packaged version (eventie)

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.

Typescript Modules Into Single JS file?

Ok, I am complete lost with this. I have just started using Typescript with Grunt JS and need some help.
I have a working Grunt file thats runs my TS and then a uglify process for site ready files, here is the config:
ts: {
default: {
files: {
'/js/builds/main.js': ['/typescript/main/build.ts'],
'/js/builds/public.js': ['/typescript/public/build.ts']
}
},
options: {
target: 'ES5',
fast: 'never',
sourceMap: false,
allowJs: true,
declaration: false,
module: 'amd'
},
},
'uglify': {
options: {
preserveComments: 'some',
},
my_target: {
files: {
'src/js/main.js': ['/js/builds/main.js'],
'src/js/public.js': ['/js/builds/public.js']
}
}
},
watch: {
'JS': {
files: [
'/js/**/*.js',
'/typescript/**/*.ts',
'/typescript/**/**/*.ts'
],
tasks: ['ts', 'uglify'],
options: {
spawn: false,
},
}
}
So now I am working on my Typescript files, but I having a lot of issues, I want to use Typescript as a module system but to output into a single file, right now its set to AMD, which needs Require JS of which I dont know.
Right now I don't have the time to learn Typescript and Require JS. So where is what I have got right now,
test.js:
export class testMe {
constructor() { }
LogingData() {
console.log( 'Data being logged...' );
}
}
Then in my build ts file,
import {testMe} from "./clients/clients";
However this needs Require JS or module loading system in order to get it to run? I have tried using commonJs but it seems support for that was removed in Typescript 1.8 (I am using 2.0).
So how do I get my Grunt / Typescript into a single standard ES5 complied code, while using modules for Typescript?
Many thanks
UPDATE
This question & answer, Typescript compile to single file does not give an answer for how to setup grunt to use Typescript into a single file! Plus the answer states that Typescript 1.8+ will fix that issue - But the version I am using does not.
I am using Grunt to compile the TS code into one standard javascript file, without the use of System or Require JS. So I can use that within my HTML code.
The end goal would be to have two single files. To explain I have lots of single .ts files for two sections, one main and the other public - I have not work on the public section, just the main one, so all my tests I been on that section.
So to layout my file/folder path:
js/
builds/
main.js < targer end file
public.js <- target end file
typescript
main/
settings/
classA.ts
somethingelse.ts
othersection/
something.ts
buildMain.ts <- *1
*1 This file then takes all the ts files, via imports (not sure if thats the correct way) and then builds the complete standard single .js file.
I hope that explains my query in more detail.
Thanks
UPDATE 2:
I would just like to add that I am getting a single file, e.g. main.js but that is not a standard Javascript complied file. I don't want to use Require JS or any other external module loading system.
I want to use external .ts files has modules import them into a 'build' file and have that file compile down to a standard self contained javascript file without the need to include require js or anything else.
Hope that clears it up a little more..
Thanks.
I believe you can use --outfile to get everything into one file. The trick is to remove import and export statements and use /// <reference path="path/to/file.ts" /> on the first lines to declare the dependency / ordering relationships. Since it is the import/export statements that produce the calls to CommonJS or Require, omitting them prevents their generation.
Ref: https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html
For two output files, you'll probably need two tsconfig.json. (I might be incorrect here.)
If you don't bother with .d.ts files you can simply use just --module=commonjs(it is and will be supported) to compile each file into .js and then browserify to concat all modules together.
I'm using CLI scripts instead of grunt but it should be obvious what it does:
$ ./node_modules/.bin/tsc --module commonjs main.ts
$ ./node_modules/.bin/browserify main.js -o bundle.js
Then you can run it like any other JavaScript from browser or CLI using node.
There's also --outFile option for tsc but this is limited only to amd and systemjs modules so I think it's easier to stick to commonjs and browserify.
browserify is an amazing tool. You can generate UMD module with --standalone parameter that works also as global or exclude any external dependencies.
I highly recommend you to read the Official Handbook: https://github.com/substack/browserify-handbook

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.

Huge number of files generated for every Angular project

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 &neArr; ]
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

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