5

When I try to build with html-webpack-plugin using index.ejs template file throws following error:

Even if I try to load as .html file or install the ejs-loader, still fails. I am not sure if ejs-loader is installing with html-webpack-plugin.

Some other people had the same issue but, their webpack version is @1 and the solution on that link did not worked for me.,

https://github.com/jantimon/html-webpack-plugin/issues/273

ERROR in ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.ejs

Module build failed: SyntaxError: Unexpected token (1:1)

Error image

src/index.ejs

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="/assets/css/bootstrap.min.css">
    <title>My Library</title>
  </head>
  <body>
    <div class="main-content"></div>
    <footer class="footer-container"><p><span>Source: </span><a href="https://github.com/arikanmstf/mylibrary">https://github.com/arikanmstf/mylibrary</a></p></footer>
  </body>
</html>

webpack.config.js:

const ExtractTextPlugin = require("extract-text-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const UglifyJSPlugin = require("uglifyjs-webpack-plugin");
const webpack = require("webpack");
const argv = require("yargs").argv;
const path = require("path");

const extractCSS = new ExtractTextPlugin("dist/style.css");

const JS_JSX_PATTERN = /\.jsx?$/;
const SCSS_PATTERN = /\.scss$/;
const ASSET_PATTERN = /\.(jpe?g|png|gif|svg|ttf|otf|eot|woff(2)?)(\?v=\d+)?$/;
const DEV_SERVER_PORT = 8080;

const configResolve = require.resolve("./src/config/" + argv.env + ".js");
const config = require("./src/config/" + argv.env + ".js");

const isProd = argv.env === 'prod';
const isDev = argv.env === 'dev';

let plugins = [extractCSS];
let rules = [
  {
    exclude: /node_modules/,
    loader: "babel-loader",
    query: {
      presets: ["react", "es2015", "stage-1"]
    }
  },
  {
    test: SCSS_PATTERN,
    use: extractCSS.extract({
      fallback: "style-loader",
      use: [{
        loader: "css-loader",
        options: { minimize: isProd }
      },
        "sass-loader"
      ]
    })
  }
];

if (isProd) {
  plugins.push(
    new UglifyJSPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production')
      }
    })
  );
}

plugins.push(
  new HtmlWebpackPlugin({
    template: 'src/index.ejs'
  })
);

rules.push({
  test: JS_JSX_PATTERN,
  exclude: /node_modules/,
  enforce: 'pre',
  loader: 'eslint-loader',
  options: {
    failOnWarning: false,
    failOnError: isProd,
    quiet: isProd
  }
});

rules.push({
  test: ASSET_PATTERN,
  exclude: /node_modules/,
  loader: 'file-loader',
  options: {
    name: 'dist/[path][name].[ext]?[hash]',
    context: 'assets'
  }
});

module.exports = {
  entry: [
    "./src/scripts/index.jsx",
    "./src/style/index.scss"
  ],
  output: {
    path: __dirname,
    publicPath: config.homeUrl,
    filename: "dist/bundle.js"
  },
  module: {
    rules: rules
  },
  resolve: {
    extensions: [".js", ".jsx"],
    modules: [
      path.resolve(__dirname, './src/scripts'),
      path.resolve(__dirname, './node_modules'),
      path.resolve(__dirname, './assets')
    ],
    alias: {
      config$: configResolve
    }
  },
  devServer: {
    port: DEV_SERVER_PORT,
    historyApiFallback: true,
    contentBase: "./"
  },
  plugins: plugins
};

package.json depencies:

"devDependencies": {
    "babel-core": "^6.2.1",
    "babel-eslint": "7.2.3",
    "babel-loader": "^7.1.0",
    "babel-preset-es2015": "^6.1.18",
    "babel-preset-react": "^6.1.18",
    "chai": "^3.5.0",
    "chai-jquery": "^2.0.0",
    "css-loader": "^0.28.4",
    "eslint": "3.19.0",
    "eslint-config-airbnb": "15.0.1",
    "eslint-loader": "1.7.1",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-jsx-a11y": "5.0.3",
    "eslint-plugin-react": "7.0.1",
    "extract-text-webpack-plugin": "^3.0.0",
    "file-loader": "^0.11.2",
    "html-webpack-plugin": "^2.29.0",
    "jquery": "^2.2.1",
    "jsdom": "^8.1.0",
    "mocha": "^2.4.5",
    "node-sass": "^4.5.3",
    "react-router-dom": "^4.1.1",
    "sass-loader": "^6.0.5",
    "style-loader": "^0.18.1",
    "uglifyjs-webpack-plugin": "^0.4.3",
    "webpack": "^3.3.0",
    "webpack-dev-server": "^2.6.1",
    "yargs": "^8.0.1"
  },
  "dependencies": {
    "axios": "^0.16.1",
    "babel-preset-stage-1": "^6.1.18",
    "prop-types": "^15.5.10",
    "qs": "^6.4.0",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "react-dropzone": "^3.13.3",
    "react-redux": "^5.0.5",
    "react-router": "^4.1.1",
    "redux": "^3.6.0",
    "redux-thunk": "^2.2.0"
  }
4
  • Do you get any more info if you turn error logging on in the plugin? new HtmlWebpackPlugin({ template: 'src/index.ejs', showErrors: true }) Commented Jul 27, 2017 at 13:06
  • same: BabelLoaderError: SyntaxError: Unexpected token (1:1) Commented Jul 27, 2017 at 13:09
  • I'm a bit rusty with webpack config but I think what's happening is your template is being bundled into a JS file which the babel-loader fails to parse. Do you get the exact same error if you specify a html filename in the HtmlWebpackPlugin? (e.g new HtmlWebpackPlugin({ template: 'src/index.ejs', filename: 'Index_Generated.html' }) Commented Jul 27, 2017 at 13:15
  • I agree. ( new HtmlWebpackPlugin({ template: 'src/index.ejs', filename: 'Index_Generated.html' }) still fails. Commented Jul 27, 2017 at 13:18

1 Answer 1

5

You forgot to add a test property on your rule for the babel-loader, which means it's applied to all files and Babel doesn't handle HTML. Technically it interprets it as JSX, but <!DOCTYPE html> is not valid JSX, because a JavaScript identifier can't contain !.

As you already have a regular expression for .js(x) the rule should be (I also changed query to options, because query is deprecated, but still works):

{
  test: JS_JSX_PATTERN,
  exclude: /node_modules/,
  loader: "babel-loader",
  options: {
    presets: ["react", "es2015", "stage-1"]
  }
},
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.