Starter package for building scalable apps with Angular 1.x, ES6, and Webpack. With focus on possibility of "slow" migration of existing applications (e.g. MS .NET). In a way that each page or set of legacy pages get replaced with a bundle, while rest of the application continues the old way.
Modular NG6 uses Gulp and Webpack together for its build system. Yes, you don't need Gulp if you're using Webpack. This is true if your build system is only responsible for file manipulation. However, ours is not.
Webpack
handles all file-related concerns:
- Transpiling from ES6 to ES5 with
Babel
- Loading HTML files as modules
- Transpiling stylesheets and appending them to the DOM
- Refreshing the browser and rebuilding on file changes
- Hot module replacement for transpiled stylesheets
- Bundling the app
- Loading all modules
- Doing all of the above for
*.spec.js
files as well
Gulp
is the orchestrator:
- Starting and calling Webpack
- Starting a development server (yes, Webpack can do this too)
- Generating boilerplate for the Angular app
Type gulp --help
to get list of all tasks and related help information
We use a componentized approach with Modular NG6. This will be the eventual standard (and particularly helpful, if using Angular UI's router) as well as a great way to ensure a tasteful transition to Angular 2, when the time is ripe. Everything--or mostly everything, as we'll explore (below)--is a component. A component is a self-contained concern--may it be a feature or strictly-defined, ever-present element of the UI (such as a header, sidebar, or footer). Also characteristic of a component is that it harnesses its own stylesheets, templates, controllers, routes, services, and specs. This encapsulation allows us the comfort of isolation and structural locality. Here's how it looks:
src/
--index.html * development index file, it is dynamically adjusted depending on running environment.
--common/ * a bundle that contains parts shared by all bundles
----components/ * shared angular components
------...
----services/ * shared angular services
------...
--bundles/ * root directory for all bundles (potentially independent sub-applications)
----test/ * test bundle
------components/ * test specific components
--------....
------directives/ * test specific directives
--------....
------services/ * test specific services
--------....
------index.js * entry file (routes, configurations, and declarations occur here)
------test.component.js * test bundle main component
------test.spec.js * test component test specs
------test.html * test component template
------test.styl * test styles
All tests are also written in ES6. We use Webpack to take care of the logistics of getting those files to run in the various browsers, just like with our client files. This is our testing stack:
- Karma
- Webpack + Babel
- Mocha
- Chai
To run tests, type
gulp test
orgulp test:runonce
in the terminal. Read more about testing below.
Project organization and naming conventions are similar to those found in the following guides:
Tools needed to run this app:
- node
- Visual Studio Code (Optional. But strongly recommended editor).
Once you dependencies installed:
npm install -g gulp typings
install global cli dependenciesnpm install
to install project specific dependencies
- ESLint
- Editor Config for Visual Studio Code
- Status Bar Commands
- TFS
- Stylus
- Spelling and Grammar Checker
Modular NG6 uses Gulp to build and launch the development environment. After you have installed all dependencies, you may run the app.
Running gulp watch
will bundle the app with webpack
, launch a development server,
and watch all files. The port will be displayed in the terminal.
List of available tasks and their command line options may change.
Run gulp --help
to get list of all available tasks with related help information.
Here's a list of most common tasks:
generate:*
- scallfolds various angular components/parts. Read below for usage details.
watch
- starts a dev server via
webpack-dev-server
, serving the client folder.
- starts a dev server via
test
(bound to test:watch)- excutes unit tests in 'watch' mode (test are re-executed when file(s) change)
To run the tests, run gulp test
or gulp test:runonce
.
Karma
combined with Webpack runs files (for specified bundles) matching *.spec.js
inside the src
folder.
This allows us to keep test files local to the component--which keeps us in good faith with continuing to build our app modularly.
The file spec.bundle.js
is the bundle file for all our spec files that Karma will run.
Be sure to define your *.spec.js
files within their corresponding component directory.
You must name the spec file like so, [name].spec.js
. If you don't want to use the .spec.js
suffix,
you must change the regex
in spec.bundle.js
to look for whatever file(s) you want.
Mocha is the testing suite and Chai is the assertion library.
If you would like to change this, see karma.conf.js
.
Use
gulp --help
to get most up to date help information about tasks and their paramenters.
Following a consistent directory structure between components offers us the certainty of predictability. We can take advantage of this certainty by creating a gulp task to automate the "instantiation" of our components.
To generate new bundle:
gulp generate:bundle -n MyNewBundle
Will create new basic bundle with related root component and intial directory structure under src/bundles/MyNewBundle
For example generate:component --name componentName -p test boilerplate task generates this:
....componentName/
......index.js // entry file where all its dependencies load
......componentName.component.js
......componentName.html
......componentName.styl // scoped to affect only its own template
......componentName.spec.js // contains passing demonstration tests
You may, of course, create these files manually, every time a new module is needed, but that gets quickly tedious.
To generate a component, run gulp generate:component --name componentName --parent test
.
The parameter following the --name
flag is the name of the component to be created.
The parameter following the --parent
flag is the name of the bundle or bundle sub-component (unlimited depth).
Example:
gulp generate:component -n componentName -p test
Assuming command above the component files will be created under src/bundles/test/components/component-name/...
.
Example:
gulp generate:service -n specialService -p test/myComponent
will generate Angular Service under src/bundles/test/components/my-component/services/...
Building testing and deploying bundles into hosting application.
See gulp publish
task and config/config.js
file where default deployment
target is defined.
... Section is under construction!
This section describes changes in hosting application that may be required in order to have seemlees bundle integration. While this section targets
MVC .NET
hosting application type, still similar adjustments can be made to other kind of hosting applications.
... Section is under construction!
Static assets are being referenced by relative URL in the templates.
In order to have those URLs to be correct after the deployment
into the hosting application, the HTML page where bundle is included
must have base tag set.
The following is a snippet of _Layout.cshtml
page in the hosting application
that sets correct base
tag.
@{
var request = HttpContext.Current.Request;
var appUrl = HttpRuntime.AppDomainAppVirtualPath;
if(!string.IsNullOrWhiteSpace(appUrl)) { appUrl += "/";}
var baseUrl = string.Format("{0}://{1}{2}", request.Url.Scheme, request.Url.Authority, appUrl);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<base href="@baseUrl"/>
...
Enabling CORS
It is recommended that during development all the data consumed by application
are supplied by mock server
(see help for gulp watch
for details).
However, it certain stages of development hosting application data may be desired.
In this case hosting application should be configured to allow CORS requests coming from
development host.
To allow CORS
requests Access-Control-Allow-Origin
header needs to be added
into response.
** please note that CORS
should usually be disabled in production build. **
- To follow this tutorial you will need to install dependencies including
Visual Studio Code
with recommended plugins.- Tutorial will refer to
d:\ngStarter
as a directory where package content was extracted to. If you have package content in different folder, please use it instead ofd:\ngStarter
.
- Start
VS Code
and ** File/Open Folder **d:\ngStarter
. - Start terminal app
Command prompt
orPowershell
andcd d:\ngStarter
.
From now on all file names will be provided relative to the package root!
In terminal window type gulp generate:bundle -n test
.
This will create bundle's initial file structure with minimal functionality
under src\bundles\test
.
In terminal window type gulp watch
. Then, point a browser to http://localhost:3000.
You will notice that gulp task doesn't finish. This is done on purpose.
While watch
task is running all code changes will be automatically picked up and
propagated into running application. You may think of it as advanced Edit and Continue
debug mode supported by Microsoft Visual Studio
Alternatively, any gulp task can be executed via
VS Code
. To do that pressCtrl+P
and type in>task
then pickTasks: Run Task
. (it may take a little while first time before available tasks will appear). Benefit of running gulp task from withinVS Code
is that it will catch all compilation errors and warnings and offer simple way to navigate to the problematic area of the code.
Keep
watch
task running.
Make small changes in any of the code files including .html, .js and .styl.
Observe automatic change propagation upon file/safe (Ctrl+S
).
Keep
watch
running.
If
gulp watch
was started in terminal window, then open new terminal window
In terminal window enter gulp generate:component -n page1 -p test
.
This command will generate simplistic Angular component and place it
under src\bundles\test\components\page1\..
.
To register new component with an application copy and paste the following
two snippets. Paste first snippet at the top of the src\bundles\test\components\index.js
after other imports. And second snippet in the module dependencies section of the file.
import page1 from './page1';
page1.name
In the header
section of the src\bundles\test\test.html
copy and paste
the following snippet:
<a ui-sref="test.home">Home</a>
<a ui-sref="test.page1">Page 1</a>
Keep observing the browser window, new component should now be available and accessable.
Keep
watch
running.
In terminal window type gulp generate:service -n testDataService -p test
Register new service with application in src\bundles\test\services\index.js
import TestDataService from './test-data.service';
And the following snippet at the very bottom of the file, right before final ';' (semicolon)
.service('testDataService', TestDataService)
Edit src\bundles\test\services\test-data.service.js
, replace $http.get
line
with
...
return this.$http.get('Home/GetTestModel').then((response) => {
...
Paste the following snippet into the footer
section of the src\bundles\test\test.html
<button ng-click="vm.onGetData()">GetData</button>
<ul>
<li ng-repeat="val in vm.dataList">{{val}}</li>
</ul>
And next one into src\bundles\test\test.component.js
within TestController
class.
onGetData() {
this.testDataService.getModel().then((result) => {
this.dataList = result.dataList || ['ERROR'];
});
}
Also declare dataList
variable in the TestController
constructor:
this.dataList = [];
Default pacakge is destributed with development helper services. One of the services
is called requestMockServerProxy
interceptor that allows serving of mock data.
Please note that data you are getting with Get Data
button and by Home/GetTestModel
url comes from src\mock.server\Home\GetTestModel.json
.
** NOTE: The Mock Server folder and file names are case sensetive! **
For best debugging experience we recommend to use
Google Chrome
as your development browser.
Drag and Drop d:\ngStarter\src
folder from file explorer into Chrome
sources tab (explorer panel),
right click within file source and 'Map to file system resource...'
Now, you can even edit files within the browser and changes will
be automatically propagated into respected source files.
To do unit test development cycle.
Start gulp test
and start editing .spec.js
files.
Do it from VS Code
for better experience, as it will help with error navigation.