3

Have a large AngularJS 1.6 project (~120 JS files), which is currently built through gulp/bower.

Looking to migrate over to using yarn & webpack, and we would prefer not to have to modify our project files just to implement webpack. Each of our AngularJS component JS files are wrapped in a IIFE, so they are already out of the global scope.

One of our gulp steps uses the gulp-angular-templatecache module, which collects all of our HTML files and neatly compacts them into a single $tmplateCache loader module.

angular.module("ourApp").run(["$templateCache", function ($templateCache) {
  $templateCache.put("/app/components/ourComponent1.html", "<div id=\"component1-html\"> ... </div>\r\n");
  $templateCache.put("/app/components/ourComponent2.html", "<div id=\"component2-html\"> ... </div>\r\n");
  // etc...
});

I have managed to figure out how to resolve most of our other build processes using webpack, but this one is giving me a problem.

I have looked at the ngtemplate-loader package, but do not think this would work for our needs because of the following:

  • Would require us to update all of our existing HTML templates to use 'require("./template.html")'
  • This would create a separate webpack module for each HTML template, which seems very inefficient.
  • Probably most important, I haven't been able to get it to work.

The current webpack configuration I have setup is based on a simple demo, and splits the project files out from the vendor files. Our project files are bundled up into a 'app.[hashcode].js' file into the /dist folder.

Ultimately, I would like to be able to inject the compiled $templateCache module, into a specific point in our final 'app.[hashcode].js' bundle file. However, right now I would be satisfied with the $templateCache definition file being created into a separate bundle file.

Is there an existing webpack plugin, or loader, or combination of plugin(s)/loader(s), that I could use to accomplish this build step? Is this even possible with webpack?

This is the base directory structure for the demo project:

/dashboard
   /app
      /assets
         /global
            global.less
         app.less
      /components
         /controllers
            dashboard.controller.js
         /directives
            yep-nope.directive.js
         /messenger
            messenger.directive.js
            messenger.html
         /services
            github-status.service.js
         dashbboard.config.js
         dashboard.module.js
      app.js
      /dist
         app.4f12bb49f144e559bd9b.js
         assets.css
         index.html
         vendor.b0a30c79aa77e0126a5c.js
   index.html
   package.json
   webpack.config.js

This is the current working webpack.config.js file:

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
   context: __dirname,  
   entry: {
      app: path.resolve(__dirname, 'app/app.js'),
      vendor: ['angular','angular-sanitize']
   },
   output: {
      path: path.resolve(__dirname, 'dist'),
      filename: '[name].[chunkhash].js'
   },
   module: {
      rules: [
      {
         test: /\.less$/,
         use: ExtractTextPlugin.extract({
            fallback: "style-loader",
            use: ['css-loader', 'less-loader']
         })
      },
      {
         test: /\.js$/,
         loader: 'ng-annotate-loader'
      },
      {
         test: /\.html$/,
         exclude: path.resolve(__dirname, 'app/index.html'),
         use: [
            { loader: 'html-loader', options: { minimize: false } }
         ]
      }]
   },
   plugins: [
      new CleanWebpackPlugin(['dist','assets/**/*.css']),
      new HtmlWebpackPlugin({   
         title: 'GitUp',
         template: 'index.html',
         inject: 'body'
      }),
      new webpack.optimize.CommonsChunkPlugin({
         name:"vendor", filename:"[name].[chunkhash].js"
      }),
      new ExtractTextPlugin('assets.css')
   ]
};  

This is the webpack 'entry' file app/app.js:

require('./assets/app.less');

require('../node_modules/angular/angular.js');
require('../node_modules/angular-sanitize/angular-sanitize.js');

require('./components/dashboard.module.js');    // Define module
require('./components/dashboard.config.js');    // Setup config

// Load in all components files, except for files already loaded above
var reqCtx = require.context('./components', true, /^(?!.*(?:dashboard\.config|dashboard\.module)).*\.js$/);
reqCtx.keys().forEach(reqCtx);

If needed, I can provide the entire sample project...

SmileyJoe
  • 51
  • 3

1 Answers1

0

This may or may not be the answer you're looking for but in the past I've used html-loader to allow me to require my component template URLs, and it worked brilliantly:

https://www.npmjs.com/package/html-loader

It just inlines the template in your bundled script.

Nat Wallbank
  • 1,377
  • 12
  • 12
  • Our goal is to have the templates fully loaded into the template cache, along with the other JS so they are available immediately. Correct me if I'm wrong (still pretty new to webpack), but does this solution mean the templates are 'require'd (or injected) at runtime? Could you point me to a functional sample for this solution? I'd like to play around with it to see if it fully would meet our needs. – SmileyJoe Oct 19 '17 at 13:14
  • Hi, no - they're require'd at build time so are available immediately in the client, i.e. no extra HTTP request required for the HTML file. It doesn't, however, pre-populate the template cache, but it looks as though this Webpack loader extends html-loader to achieve that: https://github.com/WearyMonkey/ngtemplate-loader I haven't used it personally though, as I found that html-loader was good enough for us. – Nat Wallbank Oct 19 '17 at 16:00
  • This article pretty much describes what I did, except I used html-loader rather than raw-loader: https://blog.johnnyreilly.com/2016/05/inlining-angular-templates-with-webpack.html – Nat Wallbank Oct 19 '17 at 16:06
  • Hey, thanks again for responding. Yeah, I already looked over that article a while back. Unfortunately excluded that as it still requires updating each template to use a "require()" wrapper around the template file name. Thanks for trying to help out though, I'll keep looking around and probably start digging into writing my own plugin. – SmileyJoe Oct 22 '17 at 14:41
  • No worries, good luck! Wouldn't be surprised if one already existed; all that's missing is templateUrl transform to wrap the path in a require statement. – Nat Wallbank Oct 22 '17 at 21:50
  • @SmileyJoeany luck with this? – John Ding Feb 19 '20 at 18:16