The ability to reply to discussions is limited to PRO members. Want to join in the discussion? Click here to subscribe now.

Angular with Webpack - Requiring Templates

Angular with Webpack - Requiring Templates

2:48
With Angular, most of the time you're specifying a templateUrl for your directives and states/routes. This means you need to make sure that you're loading in these templates into the $templateCache for your tests and production. Oh, and don't forget to update all your URLs whenever you move the files around! When you add in Webpack and the raw-loader, you don't need to do this anymore. Simply require the html file and your work is done!
Watch this lesson now
Avatar
egghead.io

With Angular, most of the time you're specifying a templateUrl for your directives and states/routes. This means you need to make sure that you're loading in these templates into the $templateCache for your tests and production. Oh, and don't forget to update all your URLs whenever you move the files around! When you add in Webpack and the raw-loader, you don't need to do this anymore. Simply require the html file and your work is done!

Avatar
Andrew

How would this work with the new router and "component model" for angular 1.X?

The router does do a GET on an url, and the only capacity to change that, so far as I know, is to modify the URL by providing a function mapping component names to URLs. Presently, I am loading up files in $templateCache with the karma nghtml2js plugin and in production with one or another html packer.

In reply to egghead.io
Avatar
Kent C.

With the new router, I'm sure that your components will be able to have an inline template. I'll ask Brian about it though and get back to you!

In reply to Andrew
Avatar
Ben

Try the following interceptor to get around the components issue of not specifying an inline template:

angular.module('app').factory('TemplateInterceptor', ['$templateCache', function($templateCache) {
    return {
        request: function (config) {
            if(config.url.endsWith('.html')){
                $templateCache.put(config.url, require(config.url));
            }
            return config;
        }
    };
}]);
In reply to Kent C.
Avatar
Kent C.

That wont work with webpack because all the bundling happens before runtime, so webpack can't determine what to package up with that code (because it's a runtime require). Webpack can sometimes determine dynamic requires, but only if all the information is available as part of its static analysis.

With webpack, you never really have a need to use the $templateCache anyway, unless you want to preload it elsewhere. Then that could be useful. But it'll have to be hard-coded, not dynamic like this.

In reply to Ben
Avatar
John

how does it handle ng-include in the view?

Avatar
Kent C.

You can get ng-include to work with webpack, you'd just need to pre-load the $templateCache with all the templates you want by hand which shouldn't be a big deal.

However, I would highly recommend against using ng-include and instead use an element directive with isolate scope. It is impossible to know the API to a template using ng-include but with an isolate scope directive, you define your API so from a maintainability/reasonability standpoint, you're much better off.

In reply to John
Avatar
John

got it, thanks Kent

In reply to Kent C.
Avatar
Sander

It seems that in order to have webpack require a referenced image from a directive template (e.g. <img src="../../logo.png" />), html-loader is needed instead of raw-loader.

Avatar
Kent C.

Very good point! Thank you for correcting me there. I don't actually use img tags in my app at all so it works fine for me to use the raw-loader. But most people should probably be using the html-loader.

In reply to Sander
Avatar
Elia

I've tried to use raw loader for my component's templates, but (sometimes) i get this error:

In Chrome dev tools:
http://localhost:8080/%3Cdiv%20class='page-header'%3E%20%20%3Ch1%3E%7B%7B%2…%20%20%20%20%20%3C/div%3E%20%20%20%20%3C/div%3E%20%20%3C/form%3E%3C/div%3E 414 (Request-URI Too Large)

In console:
ENAMETOOLONG

How i can fix it?
Thanks

Avatar
Kent C.

That's probably happening because you're still using templateUrl rather than template

In reply to Elia
Avatar
Elia

You right! I've found that i use it in my router.
I've changed my components template, but not the router.
Now works, but i've an error: "jQuery is not defined".
Strange because i don't use it, maybe it's some package.
Webpack can't include it automatically if it's a dependency?

In reply to Kent C.
Avatar
Elia

I've figured it out installing jquery with npm and adding this loader:

test: /bootstrap\/js\//,
loader: 'imports?jQuery=jquery'

In reply to Elia
Avatar
J.C. Francis III

What do the package.json scripts look like for Windows? I can't get the build script working.

Avatar
Kent C.

Yeah, sorry. Try installing and using cross-env for the build script:

npm install -D cross-env

Then update build to:

"build": "cross-env NODE_ENV=production webpack && cp app/index.html dist/index.html"

Note, I edited the script a bit because you don't need node or to point directly to node_modules/.bin/webpack.

Good luck!

In reply to J.C. Francis III
Avatar
J.C. Francis III

Thanks this worked. I used xcopy [source] [destination] /Y to cp. Thanks again.

In reply to Kent C.
Avatar
Tim

Followed steps in this video but I'm getting a termial error when I ran webpack. Any ideas?

ERROR in ./scripts/Directive/socialMediabuttons.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./components/social-media-buttons.html in /app/scripts/Directive
resolve file

Avatar
Kent C.

That error would seem to indicate that webpack is unable to find a file in /app/scripts/Directive/components/social-media-buttons.html. If the file is actually there, my guess is that you may be setting your context incorrectly with the leading / in /app (it needs to be a full path, but it you probably don't mean the app directory in your root directory).

Good luck!

In reply to Tim
Avatar
Joseph

I'm getting the following error:

in ./app/directives/kcd-hello.html
Module parse failed: /Users/joe/Dev/angular-webpack/app/directives/kcd-hello.html Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token (1:0)

In my webpack config:

modules: {
        loaders: [
            {
                test: /\.js$/,
                loader: 'babel',
                exclude: '/node_modules'
            },
            {
                test: /\.html$/,
                loader: "raw",
                exclude: '/node_modules'
            }
        ]
    }

And in my directive:

module.exports = function (ngModule) {
    ngModule.directive("kcdHello", function () {
        return {
            restrict: 'E',
            scope: {},
            template: require('./kcd-hello.html'),
            controllerAs: 'vm',
            controller: function (){
                var vm = this;
                vm.greeting = 'hello webpack'
            }
        }
    })
}

Any ideas why i'm still getting the error? My template is just a simple div with {{vm.greeting)). I also tried html-loader, but that failed too.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?