WearyMonkey / ngtemplate-loader

Include AngularJS templates in the Webpack bundle and preload the template cache.
MIT License
238 stars 78 forks source link

Loader injects strange text in generated html file. ERROR "window is not defined " if html-loader is after ngtemplate-loader in config #80

Closed Vitenok closed 6 years ago

Vitenok commented 6 years ago

Hi, I'm trying to switch my Angular 1.5.3 app to use Webpack 3.10.0 for bundling and using ngtemplate-loader to make angular templates work. Would appreciate any help since I'm stuck with this for quite a long time.

The problem I'm getting now is strange text which wraps <html></html> tags in generated html file :

Generated wdist/index.html:

var path = 'C:/source/kjopslosning-smb/ksmb-frontend/app/index-webpack.html';
var html = <!DOCTYPE html>
<html lang="no" class="no-js" ng-app="ksmbApp">
     <head>.....</head>
     <body>.....</body>
</html>
;
window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
module.exports = path;

Project structure

+app
+--fonts
+--images
+--styles
+--scripts
+------app.js
+------entry.js
+------controllers
+------sevices
+------directives
+--views (here are all the templates)
+--index-webpack.html
+webpack.config.js
+package.json

webpack.config.js

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

const extractLess = new ExtractTextPlugin({
  filename: "wbpk-bundle.css",
});

const modules = {
  rules: [
    {
      test: /\.html$/,
      exclude: /node_modules/,
      use: [

        {
          loader: 'html-loader',
          options: {
            root: path.resolve(__dirname, './app/images'),
            attrs: ['img:src', 'link:href']
          }
        },
        {
          loader: 'ngtemplate-loader?relativeTo=' + __dirname + '/app/views',
          options: {
            exclude: path.resolve(__dirname, './app/index-webpack.html'),
          }
        },
      ]
    },
    {
      test: /\.(png|svg|jpg|gif|ico)$/,
      use: [
        {
          loader: 'file-loader',
        }
      ]
    },
    {
      test: /\.less$/,
      use: extractLess.extract({
        use: [{
          loader: "css-loader"
        }, {
          loader: "less-loader",
        }],
        // use style-loader in development
        fallback: "style-loader"
      })
    },
    {
      test: /\.(woff|woff2|eot|ttf|otf)$/,
      use: [
        'file-loader'
      ]
    }
  ]
};

module.exports = {
  entry: path.resolve(__dirname, './app/scripts/entry.js'),
  output: {
    path: __dirname + '/wdist',
    // filename: 'app.bundle.js',
    filename: '[name].bundle.js',
    publicPath: '/ksmb/app'
  },
  devtool: 'inline-source-map',
  module: modules,
  devServer: {
    port: 9000,
    contentBase: './wdist',
    openPage: 'ksmb/app',
    hot: false
  },
  plugins: [
    new CleanWebpackPlugin(['wdist']),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: path.resolve(__dirname, './app/index-webpack.html'),
    }),
    extractLess
  ],
};

Templates are injected in two manners: Either with ng-include <div ng-include="require('../views/header.html')"></div>, or like this:

 $routeProvider
     .when('/about', {
      template: require('../views/about.html'),
      controller: 'AboutCtrl',
      controllerAs: 'aboutCtrl',
      title: 'Selskapsinformasjon',
      resolve: {
        initComplete: initComplete
      }
    })
});

Generated main.bundle.js seems to have srtingified templates:

.............................................
/***/ }),
/* 27 */
/***/ (function(module, exports) {

module.exports = "var path = 'C:/source/kjopslosning-smb/ksmb-frontend/app/views/about.html';\nvar html = <section class=\"ffe-section-wrapper\" mg-controller=\"AboutCtrl as aboutCtrl\">\r\n  <div class=\"ffe-content-container ffe-content-container--lg ffe-content-container--text-left\">\r\n    <a href=\"\" class=\"ffe-link-text ksmb-to-previous\" ng-click=\"aboutCtrl.back()\" ng-bind-html=\"::texts['common.back']\"></a>\r\n  </div>\r\n</section>\r\n<section>\r\n  <div class=\"ffe-content-container ffe-content-container--text-left content-wrapper\">\r\n    <h1 class=\"ffe-h2\" ng-bind-html=\"::texts['about.title']\"></h1>\r\n    <p class=\"ffe-body-paragraph\" ng-bind-html=\"::texts['about.insurance.body']\"></p>\r\n    <p class=\"ffe-body-paragraph\" ng-bind-html=\"::texts['about.damageinsurance.body']\"></p>\r\n  </div>\r\n</section>\r\n;\nwindow.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);\nmodule.exports = path;";

/***/ }),
/* 28 */
/***/ (function(module, exports) {

module.exports = "var path = 'C:/source/kjopslosning-smb/ksmb-frontend/app/views/terms.html';\nvar html = <section class=\"ffe-section-wrapper\" mg-controller=\"TermsCtrl as termsCtrl\">\r\n  <div class=\"ffe-content-container ffe-content-container--lg ffe-content-container--text-left\">\r\n    <a href=\"\" class=\"ffe-link-text ksmb-to-previous\" ng-click=\"termsCtrl.back()\" ng-bind-html=\"::texts['common.back']\"></a>\r\n  </div>\r\n</section>\r\n<section>\r\n  <div class=\"ffe-content-container ffe-content-container--text-left content-wrapper\">\r\n    <h1 class=\"ffe-h2\" ng-bind-html=\"::texts['terms.title']\"></h1>\r\n    <div ng-bind-html=\"::texts['terms.body']\"></div>\r\n  </div>\r\n</section>\r\n;\nwindow.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);\nmodule.exports = path;";

/***/ }),
...............................................

So page looks like this when webpack-server is started: wbpk :

Please help to get it work

P.S.

After changing order of loaders (ngtemplate-loader first and html-loader after) I'm getting error:

ERROR in   Error: C:\source\kjopslosning-smb\ksmb-frontend\app\index-webpack.html:73
  window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
  ^
  ReferenceError: window is not defined

As mentioned in this issue #41 exclude needs to be addded to config. This is confusing to me coz I already have it:

options: {
            exclude: path.resolve(__dirname, './app/index-webpack.html')

          }

Any thoughts?

Vitenok commented 6 years ago

index-webpack.html was not excluded because exclude needs to be not inside options. This part is not covered in documentation at all which is kinda sad @WearyMonkey, probably it is good idea to write somethind about this in docs. My config partial now looks like this:

{
      test: /\.html$/,
      exclude: [ path.resolve(__dirname, './node_modules'), path.resolve(__dirname, './app/index-webpack.html')],
      use: [
        {
          loader: 'ngtemplate-loader',
          options: {
                relativeTo: path.resolve(__dirname + '/app/views'),
          }
        },
        {
          loader: 'html-loader',
          options: {
            root: path.resolve(__dirname, './app/images'),
            attrs: ['img:src', 'link:href']

          }
        },
      ]
    },

I also had to remove '?relativeTo=' + __dirname + '/app/views' part from loader definition as it was causing errors. I beleive this syntax does not work in Webpak 3.