Angular Universal server breaks when I replace my imports from lodash to lodash-es. But when I run ng serve
, things are fine. I want to use lodash-es so I can cherry-pick lodash functions in my Angular SPA and shrink bundle size.
Steps I took: npm uninstalled lodash, npm installed lodash-es, and replaced my imports like this:
From: import { find as _find } from "lodash";
To: import { find as _find } from "lodash-es"
;
This is the server error I am getting:
/usr/src/app/node_modules/lodash-es/lodash.js:10export { default as add } from './add.js';^^^^^^SyntaxError: Unexpected token export at createScript (vm.js:80:10) at Object.runInThisContext (vm.js:139:10) at Module._compile (module.js:599:28) at Object.Module._extensions..js (module.js:646:10) at Module.load (module.js:554:32) at tryModuleLoad (module.js:497:12) at Function.Module._load (module.js:489:3) at Module.require (module.js:579:17) at require (internal/module.js:11:18) at Object.<anonymous> (/usr/src/app/dist/server.js:246:18)
server.ts
import "zone.js/dist/zone-node";import "reflect-metadata";import { renderModuleFactory } from "@angular/platform-server";import { enableProdMode } from "@angular/core";import * as express from "express";import * as minifyHTML from "express-minify-html";import { join } from "path";import { readFileSync } from "fs";// Faster server renders w/ Prod mode (dev mode never needed)enableProdMode();// Express serverconst app = express();const PORT = process.env.PORT || 4000;const DIST_FOLDER = join(process.cwd(), "dist");// Our index.html we'll use as our templateconst template = readFileSync( join(DIST_FOLDER, "browser", "index.html")).toString();// * NOTE :: leave this as require() since this file is built Dynamically from webpackconst { AppServerModuleNgFactory, LAZY_MODULE_MAP} = require("./dist/server/main.bundle");// Express Engineimport { ngExpressEngine } from "@nguniversal/express-engine";// Import module map for lazy loadingimport { provideModuleMap } from "@nguniversal/module-map-ngfactory-loader";app.use( minifyHTML({ override: true, exception_url: false, htmlMinifier: { removeComments: true, collapseWhitespace: true, collapseBooleanAttributes: true, removeAttributeQuotes: true, removeEmptyAttributes: true, minifyJS: true, minifyCSS: true } }));// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)app.engine("html", ngExpressEngine({ bootstrap: AppServerModuleNgFactory }));app.set("view engine", "html");app.set("views", join(DIST_FOLDER, "browser"));/* - Example Express Rest API endpoints - app.get('/api/**', (req, res) => { });*/// Server static files from /browserapp.get("*.*", express.static(join(DIST_FOLDER, "browser"), { maxAge: "1y" }));// ALl regular routes use the Universal engineapp.get("*", (req, res) => { res.render("index", { req });});// Start up the Node serverapp.listen(PORT, () => { console.log(`Node Express server listening on http://localhost:${PORT}`);});
This is webpack.server.config.js (might be related?):
const path = require("path");const webpack = require("webpack");const nodeExternals = require("webpack-node-externals");module.exports = { entry: { server: "./server.ts" }, resolve: { extensions: [".ts", ".js"] }, target: "node", externals: [nodeExternals()], output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, module: { rules: [{ test: /\.ts$/, loader: "ts-loader" }] }, plugins: [ new webpack.DefinePlugin({ window: undefined, document: undefined }), new webpack.ContextReplacementPlugin( /(.+)?angular(\\|\/)core(.+)?/, path.join(__dirname, "src"), // location of your src {} // a map of your routes ), new webpack.ContextReplacementPlugin( /(.+)?express(\\|\/)(.+)?/, path.join(__dirname, "src") ) ]};