├── .babelrc
├── .eslintrc
├── .github
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .travis.yml
├── LICENSE
├── Procfile
├── README.md
├── appveyor.yml
├── contributing.md
├── package.json
├── server.js
├── src
├── app.js
├── app.routing.js
├── app.states.js
├── core
│ └── bootstrap.js
├── index.html
└── pages
│ ├── blog
│ ├── blog.module.js
│ ├── blog.service.js
│ └── blog.view.html
│ └── home
│ ├── about
│ ├── about.module.js
│ └── about.view.html
│ ├── home.module.js
│ ├── home.module.routing.js
│ ├── home.module.states.js
│ └── index
│ ├── index.module.js
│ └── index.view.html
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "env",
5 | {
6 | "targets": {
7 | "browsers": [
8 | "last 2 versions",
9 | "safari 7"
10 | ]
11 | }
12 | }
13 | ]
14 | ],
15 | "plugins": [
16 | "syntax-dynamic-import"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint:recommended",
3 | "parser": "babel-eslint",
4 | "parserOptions": {
5 | "ecmaVersion": 6,
6 | "sourceType": "module",
7 | "ecmaFeatures": {
8 | "impliedStrict": false
9 | }
10 | },
11 | "env": {
12 | "browser": true,
13 | "node": true,
14 | "es6": true
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | **Do you want to request a *feature* or report a *bug*?**
6 |
7 |
8 |
9 |
10 | **What is the current behavior?**
11 |
12 | **If the current behavior is a bug, please provide the steps to reproduce.**
13 |
14 |
15 |
16 |
17 |
18 | **What is the expected behavior?**
19 |
20 | **If this is a feature request, what is motivation or use case for changing the behavior?**
21 |
22 | **Please mention other relevant information such as the browser version, Node.js version, AngularJS version and Operating System.**
23 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | **What kind of changes does this PR introduce?**
4 |
5 |
6 |
7 | **Did you add tests for your changes?**
8 |
9 |
10 |
11 | **Summary**
12 |
13 |
14 |
15 |
16 | **Does this PR introduce a breaking change?**
17 |
18 |
19 |
20 | **Other information**
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | test/report
4 | *bundle.js
5 | npm-debug.log
6 | dist
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 |
4 | cache:
5 | directories:
6 | - "node_modules" # NPM packages
7 |
8 | matrix:
9 | include:
10 | - os: linux
11 | node_js: "8"
12 | env: NO_WATCH_TESTS=1
13 | - os: osx
14 | node_js: "8"
15 | env: NO_WATCH_TESTS=1
16 | allow_failures:
17 | - os: osx
18 | fast_finish: true
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Vitalii Rybka
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: npm run heroku
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | |
8 |
9 | +
10 | |
11 |
12 |
13 |
14 |
15 | |
16 |
17 | +
18 | |
19 |
20 |
21 |
22 |
23 | |
24 |
25 | =
26 | |
27 |
28 | :heart_eyes:
29 | |
30 |
31 |
32 |
33 | [](https://github.com/var-bin/angularjs-lazyload/blob/master/LICENSE)
34 | [](https://github.com/var-bin/angularjs-lazyload)
35 | [](https://travis-ci.org/var-bin/angularjs-lazyload)
36 | [](https://ci.appveyor.com/project/var-bin/angularjs-lazyload)
37 | [](https://twitter.com/var_bincom)
38 | [](https://twitter.com/intent/tweet?text=Load%20AngularJS%20modules%20on%20demand%20via%20Webpack,%20UI%20Router,%20and%20ocLazyLoad%20by%20%40var_bincom:&url=https%3A%2F%2Fgithub.com%2Fvar-bin%2Fangularjs-lazyload&hashtags=angularjs%2CWebpack%2Cuirouter%2CocLazyLoad)
39 |
40 | # angularjs-lazyload
41 | This repo is existed to help you to understand how to implement lazyload technique via Webpack and a little bit of magic.
42 |
43 | ## Install
44 | 1. Do `git clone` stuff.
45 | 2. `cd angularjs-lazyload`.
46 | 3. `npm install`.
47 | 4. Run **dev** mode: `npm start`.
48 |
49 | The init state of App:
50 |
51 | ```
52 | project-root
53 | ├── src
54 | │ ├── core
55 | │ │ ├── bootstrap.js
56 | │ ├── pages
57 | │ │ ├── blog
58 | │ │ │ ├── blog.module.js
59 | │ │ │ ├── blog.service.js
60 | │ │ │ ├── blog.view.html
61 | │ │ ├── home
62 | │ │ │ ├── about
63 | │ │ │ │ ├── about.module.js
64 | │ │ │ │ ├── about.view.html
65 | │ │ │ ├── index
66 | │ │ │ │ ├── index.module.js
67 | │ │ │ │ ├── index.view.html
68 | │ │ │ ├── home.module.js
69 | │ │ │ ├── home.module.routing.js
70 | │ │ │ ├── home.module.states.js
71 | ├── app.js
72 | ├── app.routing
73 | ├── app.states.js
74 | ├── index.html
75 | ```
76 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # Test against the latest version of this Node.js version
2 | environment:
3 | matrix:
4 | # node.js
5 | - nodejs_version: "7"
6 |
7 | # Install scripts. (runs after repo cloning)
8 | install:
9 | # Get the latest stable version of Node.js or io.js
10 | - ps: Install-Product node $env:nodejs_version
11 | # install modules
12 | - npm install
13 |
14 | # Post-install test scripts.
15 | test_script:
16 | # Output useful info for debugging.
17 | - node --version
18 | - npm --version
19 | - npm t
20 |
21 | # cache npm modules
22 | cache:
23 | - node_modules # local npm modules
24 | - '%APPDATA%\npm-cache' # npm cache
25 |
26 | # Don't actually build.
27 | build: off
28 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | *1 - Fork it!*
4 |
5 | *2 - Clone*
6 |
7 | *3 - Create your feature branch:*
8 | ```bash
9 | $ git checkout -b my-new-feature origin/master
10 | ```
11 | *4 - Commit your changes:*
12 | ```bash
13 | $ git commit -m 'Add some feature'
14 | ```
15 | *5 - Push to the branch:*
16 | ```bash
17 | $ git push origin my-new-feature
18 | ```
19 | *6 - Submit a pull request*
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angularjs-lazyload",
3 | "version": "1.0.0",
4 | "description": "Load AngularJS modules on demand via Webpack, UI Router and ocLazyLoad",
5 | "scripts": {
6 | "start": "webpack-dev-server --devtool inline-source-map --env.dev",
7 | "build": "webpack --env.production",
8 | "test": "eslint --report-unused-disable-directives --ext .js src/",
9 | "heroku": "npm run build && node server.js",
10 | "size": "size-limit",
11 | "bundle-buddy": "bundle-buddy"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/var-bin/angularjs-lazyload.git"
16 | },
17 | "homepage": "https://github.com/var-bin/angularjs-lazyload",
18 | "author": "Vitalii Rybka @var_bincom",
19 | "license": "MIT",
20 | "dependencies": {
21 | "@uirouter/angularjs": "^1.0.11",
22 | "angular": "^1.6.6",
23 | "body-parser": "^1.18.2",
24 | "express": "^4.16.2",
25 | "oclazyload": "^1.1.0",
26 | "webpack": "^3.8.1",
27 | "webpack-dev-server": "^2.9.4"
28 | },
29 | "devDependencies": {
30 | "babel-core": "^6.26.0",
31 | "babel-eslint": "^8.0.3",
32 | "babel-loader": "^7.1.2",
33 | "babel-plugin-syntax-dynamic-import": "^6.18.0",
34 | "babel-preset-env": "^1.6.1",
35 | "bundle-buddy": "^0.2.1",
36 | "clean-webpack-plugin": "^0.1.17",
37 | "css-loader": "^0.28.7",
38 | "eslint": "^4.12.1",
39 | "eslint-loader": "^1.9.0",
40 | "extract-text-webpack-plugin": "^3.0.2",
41 | "html-webpack-plugin": "^2.30.1",
42 | "npm-check-updates": "^2.13.0",
43 | "raw-loader": "^0.5.1",
44 | "size-limit": "^0.14.0",
45 | "style-loader": "^0.19.0",
46 | "uglifyjs-webpack-plugin": "^1.1.2",
47 | "webpack-bundle-analyzer": "^2.9.2"
48 | },
49 | "keywords": [
50 | "AngularJS",
51 | "lazyLoad",
52 | "webpack",
53 | "ocLazyLoad",
54 | "uiRouter"
55 | ],
56 | "size-limit": [
57 | {
58 | "limit": "300 KB",
59 | "webpack": false,
60 | "path": "dist/*.js"
61 | }
62 | ]
63 | }
64 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | // server.js
2 |
3 | "use strict";
4 |
5 | const express = require("express");
6 | const bodyParser = require("body-parser");
7 | const path = require("path");
8 |
9 | const app = express();
10 | app.use(bodyParser.json());
11 |
12 | // Create link to AngularJS build directory
13 | const distDir = path.join(__dirname, "dist");
14 | app.use(express.static(distDir));
15 |
16 | // Initialize the app.
17 | const server = app.listen(process.env.PORT || 8080, () => {
18 | const port = server.address().port;
19 |
20 | console.info(`App now running on port: ${port}`);
21 | });
22 |
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | // app.js
2 |
3 | "use strict";
4 |
5 | import angular from "angular";
6 | import "@uirouter/angularjs";
7 | import "oclazyload";
8 |
9 | import "./pages/home/home.module";
10 | import { appRouting } from "./app.routing";
11 |
12 | const LAZY_APP = angular
13 | .module("lazyApp", [
14 | "ui.router",
15 | "oc.lazyLoad",
16 | "homeModule"
17 | ])
18 | .config(appRouting);
19 |
20 | export { LAZY_APP };
21 |
--------------------------------------------------------------------------------
/src/app.routing.js:
--------------------------------------------------------------------------------
1 | // app.routing.js
2 |
3 | "use strict";
4 |
5 | import { appBlog } from "./app.states";
6 |
7 | appRouting.$inject = ["$urlRouterProvider", "$stateProvider"];
8 |
9 | function appRouting($urlRouterProvider, $stateProvider) {
10 | $urlRouterProvider.otherwise("/home");
11 |
12 | $stateProvider.state(appBlog);
13 | }
14 |
15 | export { appRouting };
16 |
--------------------------------------------------------------------------------
/src/app.states.js:
--------------------------------------------------------------------------------
1 | // app.states.js
2 |
3 | "use strict";
4 |
5 | const appBlog = {
6 | name: "blog",
7 | url: "/blog",
8 | component: "blogComponent",
9 | lazyLoad: ($transition$) => {
10 | const $ocLazyLoad = $transition$.injector().get("$ocLazyLoad");
11 |
12 | return import(/* webpackChunkName: "blog.module" */ "./pages/blog/blog.module")
13 | .then(mod => $ocLazyLoad.load(mod.BLOG_MODULE))
14 | .catch(err => {
15 | throw new Error("Ooops, something went wrong, " + err);
16 | });
17 | }
18 | };
19 |
20 | export { appBlog };
21 |
--------------------------------------------------------------------------------
/src/core/bootstrap.js:
--------------------------------------------------------------------------------
1 | // bootstrap.js
2 |
3 | "use strict";
4 |
5 | import angular from "angular";
6 | import { LAZY_APP } from "../app";
7 |
8 | angular.bootstrap(document, [LAZY_APP.name], {
9 | strictDi: true
10 | });
11 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Lazy load AngularJS with Webpack
8 |
9 |
11 |
14 |
15 |
24 |
25 |
26 |
29 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/pages/blog/blog.module.js:
--------------------------------------------------------------------------------
1 | // blog.module.js
2 |
3 | import angular from "angular";
4 | import { BlogService } from "./blog.service";
5 |
6 | class BlogController {
7 | constructor(BlogService) {
8 | this.title = "BlogComponent";
9 | this.BlogService = BlogService;
10 | this.repos = [];
11 | }
12 |
13 | $onInit() {
14 | this.getArticles();
15 | }
16 |
17 | getArticles() {
18 | this.BlogService.getData()
19 | .then((data) => {
20 | this.repos = data;
21 | });
22 | }
23 | }
24 |
25 | BlogController.$inject = ["BlogService"];
26 |
27 | class BlogComponent {
28 | constructor() {
29 | this.template = require("./blog.view.html");
30 | this.controller = BlogController;
31 | }
32 | }
33 |
34 | const BLOG_MODULE = angular
35 | .module("blog.module", [])
36 | .component("blogComponent", new BlogComponent())
37 | .service("BlogService", BlogService);
38 |
39 | export { BLOG_MODULE };
40 |
--------------------------------------------------------------------------------
/src/pages/blog/blog.service.js:
--------------------------------------------------------------------------------
1 | // blog.service.js
2 |
3 | class BlogService {
4 | constructor($http) {
5 | this.$http = $http;
6 | this.API_URL = "https://api.github.com";
7 | }
8 |
9 | getData() {
10 | const REPOS = "users/var-bin/repos";
11 | const URL = `${this.API_URL}/${REPOS}`;
12 |
13 | return this.$http.get(URL)
14 | .then((response) => response.data);
15 | }
16 | }
17 |
18 | BlogService.$inject = ["$http"];
19 |
20 | export { BlogService };
21 |
--------------------------------------------------------------------------------
/src/pages/blog/blog.view.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Only blog.module.chunk.js
5 |
6 |
7 | -
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/pages/home/about/about.module.js:
--------------------------------------------------------------------------------
1 | // about.module.js
2 |
3 | "use strict";
4 |
5 | import angular from "angular";
6 |
7 | class HomeAboutController {
8 | constructor() {
9 | this.title = "HomeAboutComponent";
10 | }
11 | }
12 |
13 | class HomeAboutComponent {
14 | constructor() {
15 | this.template = require("./about.view.html");
16 | this.controller = HomeAboutController;
17 | }
18 | }
19 |
20 | const HOME_ABOUT_MODULE = angular
21 | .module("home.about.module", [])
22 | .component("homeAboutComponent", new HomeAboutComponent());
23 |
24 | export { HOME_ABOUT_MODULE };
25 |
--------------------------------------------------------------------------------
/src/pages/home/about/about.view.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Only about.module.chunk.js
5 |
--------------------------------------------------------------------------------
/src/pages/home/home.module.js:
--------------------------------------------------------------------------------
1 | // home.module.js
2 |
3 | "use strict";
4 |
5 | import angular from "angular";
6 | import { homeRouting } from "./home.module.routing";
7 |
8 | const HOME_MODULE = angular
9 | .module("homeModule", [])
10 | .config(homeRouting);
11 |
12 | export { HOME_MODULE };
13 |
--------------------------------------------------------------------------------
/src/pages/home/home.module.routing.js:
--------------------------------------------------------------------------------
1 | // home.module.routing.js
2 |
3 | "use strict";
4 |
5 | import { homeIndex, homeAbout } from "./home.module.states";
6 |
7 | homeRouting.$inject = ["$urlRouterProvider", "$stateProvider"];
8 |
9 | function homeRouting($urlRouterProvider, $stateProvider) {
10 | $urlRouterProvider.otherwise("/home");
11 |
12 | $stateProvider.state(homeIndex);
13 | $stateProvider.state(homeAbout);
14 | }
15 |
16 | export { homeRouting };
17 |
--------------------------------------------------------------------------------
/src/pages/home/home.module.states.js:
--------------------------------------------------------------------------------
1 | // home.module.states.js
2 |
3 | "use scrict";
4 |
5 | const homeIndex = {
6 | name: "home",
7 | url: "/home",
8 | component: "homeComponent",
9 | lazyLoad: ($transition$) => {
10 | const $ocLazyLoad = $transition$.injector().get("$ocLazyLoad");
11 |
12 | return import(/* webpackChunkName: "index.module" */ "./index/index.module")
13 | .then(mod => $ocLazyLoad.load(mod.HOME_INDEX_MODULE))
14 | .catch(err => {
15 | throw new Error("Ooops, something went wrong, " + err);
16 | });
17 | }
18 | };
19 |
20 | const homeAbout = {
21 | name: "home.about",
22 | url: "/about",
23 | component: "homeAboutComponent",
24 | lazyLoad: ($transition$) => {
25 | const $ocLazyLoad = $transition$.injector().get("$ocLazyLoad");
26 |
27 | return import(/* webpackChunkName: "about.module" */ "./about/about.module")
28 | .then(mod => $ocLazyLoad.load(mod.HOME_ABOUT_MODULE))
29 | .catch(err => {
30 | throw new Error("Ooops, something went wrong, " + err);
31 | });
32 | }
33 | };
34 |
35 | export { homeIndex, homeAbout };
36 |
--------------------------------------------------------------------------------
/src/pages/home/index/index.module.js:
--------------------------------------------------------------------------------
1 | // index.module.js
2 |
3 | "use strict";
4 |
5 | import angular from "angular";
6 |
7 | class HomeIndexController {
8 | constructor() {
9 | this.title = "HomeComponent";
10 | }
11 | }
12 |
13 | class HomeIndexComponent {
14 | constructor() {
15 | this.template = require("./index.view.html");
16 | this.controller = HomeIndexController;
17 | }
18 | }
19 |
20 | const HOME_INDEX_MODULE = angular
21 | .module("home.module", [])
22 | .component("homeComponent", new HomeIndexComponent());
23 |
24 | export { HOME_INDEX_MODULE };
25 |
--------------------------------------------------------------------------------
/src/pages/home/index/index.view.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Only index.module.chunk.js
5 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const path = require("path");
4 | const webpack = require("webpack");
5 | const HtmlWebpackPlugin = require("html-webpack-plugin");
6 | const CleanWebpackPlugin = require("clean-webpack-plugin");
7 | const UglifyJSPlugin = require("uglifyjs-webpack-plugin");
8 | const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
9 |
10 | const devServer = {
11 | contentBase: path.resolve("dist"),
12 | hot: true,
13 | host: process.env.host || "localhost",
14 | port: process.env.PORT || 5000
15 | };
16 |
17 | const webpackConfig = (env) => {
18 | const config = {
19 | entry: {
20 | app: path.resolve("./src/core/bootstrap.js")
21 | },
22 | output: {
23 | filename: "bundle.js",
24 | chunkFilename: "[name].chunk.js",
25 | path: path.join(__dirname, "dist")
26 | },
27 | module: {
28 | rules: [
29 | // eslint
30 | {
31 | enforce: "pre",
32 | test: /\.js$/,
33 | exclude: /node_modules/,
34 | loader: "eslint-loader",
35 | },
36 |
37 | // babel
38 | {
39 | test: /\.js$/,
40 | exclude: /node_modules/,
41 | loader: "babel-loader"
42 | },
43 |
44 | // html
45 | {
46 | test: /\.html$/,
47 | loader: "raw-loader",
48 | exclude: path.resolve("./src/index.html")
49 | },
50 |
51 | // css
52 | {
53 | test: /\.css$/,
54 | use: [{
55 | loader: "style-loader"
56 | }, {
57 | loader: "css-loader"
58 | }]
59 | }
60 | ]
61 | },
62 | plugins: [
63 | new HtmlWebpackPlugin({
64 | filename: "index.html",
65 | template: path.resolve("./src/index.html")
66 | }),
67 |
68 | new webpack.optimize.CommonsChunkPlugin({
69 | name: "common",
70 | filename: "common.js",
71 | minChunks: (module) => {
72 | // this assumes your vendor imports exist in the node_modules directory
73 | return module.context && module.context.indexOf("node_modules") !== -1;
74 | }
75 | }),
76 |
77 | new CleanWebpackPlugin(["dist"]),
78 |
79 | new BundleAnalyzerPlugin()
80 | ]
81 | };
82 |
83 | if (env && env.dev) {
84 | config.devServer = devServer;
85 | config.plugins.push(
86 | new webpack.NamedModulesPlugin(),
87 | new webpack.HotModuleReplacementPlugin()
88 | );
89 | }
90 |
91 | if (env && env.production) {
92 | config.devtool = "source-map";
93 | config.plugins.push(
94 | new UglifyJSPlugin({
95 | uglifyOptions: {
96 | warnings: true
97 | },
98 | sourceMap: true
99 | }),
100 | new webpack.DefinePlugin({
101 | "process.env.NODE_ENV": JSON.stringify("production")
102 | })
103 | );
104 | }
105 |
106 | return config;
107 | };
108 |
109 | module.exports = webpackConfig;
110 |
--------------------------------------------------------------------------------