TLDR: Aurelia app, bundled with webpack, can't load in browser - console shows error: can't find module with id: main. I think that means it can't find the entrypoint. Running out of things to try.
I work on an Aurelia application.
We use webpack for bundling our front-end code.
It all worked great until the past couple days. (recently we added aurelia-dialog, which worked fine, but we had to do some npm updates to be able to get it to work, etc.)
There were a several npm dependency issues that needed resolving, but I got them eventually...
One particularly annoying one was that gulp used to be included in our package.json as "gulp": "github:gulpjs/gulp#4.0 but I guess that git branch was removed, so between that and whatever other npm issues, they all needed to be updated to "gulp": "4.0" which is chill - apart from it then causing us to then go and have to start the horrendous long train of npm dependency resolutions.
Now, however, I'm stuck at at point where there are no errors with the npm packages, nor errors coming from webpack's compilation process, nor any tslint errors. However, the app is broken, and even in other branches which haven't been touched, it's also having issues.
The error is:
Error: Unable to find module with ID: main
at WebpackLoader. (https://localhost:44399/dist/app.bundle.js?v=18.11.05&v=QnXnhS1zNjvTNWq1CN7QzBCr2ti1BVIVEjGB_ewbuj0:9435:35)
at step (https://localhost:44399/dist/app.bundle.js?v=18.11.05&v=QnXnhS1zNjvTNWq1CN7QzBCr2ti1BVIVEjGB_ewbuj0:9296:23)
If I'm understanding correctly (I'm not the developer who set this app up, and he's no longer around), the "main" being referenced in the error comes from the aurelia-app="main" attribute within the <body> element in wwwroot/dist/index.html :
(see bottom for directory stucture)
index.html
<html>
<head>
<meta charset="utf-8">
<title>Aurelia Navigation Skeleton</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="/">
<!-- imported CSS are concatenated and added automatically -->
</head>
<body aurelia-app="main">
<script type="text/javascript" src="/app.bundle.js"></script><script type="text/javascript" src="/vendor.bundle.js"></script></body>
</html>
the value "main", I believe is supposed to reference the src/main.ts:
(I've tried changing it to: main.ts, src/main.ts, src/main, ../../src/main.ts, etc -- none of them worked or even changed the error message, which makes me feel like that's not the right place to be looking.)
main.ts
// we want font-awesome to load as soon as possible to show the fa-spinner
import {Aurelia} from 'aurelia-framework'
import environment from './environment';
import {PLATFORM} from 'aurelia-pal';
import * as Bluebird from 'bluebird';
// remove if you don't want a Promise polyfill (remove also from webpack.config.js)
Bluebird.config({ warnings: { wForgottenReturn: false } });
export function configure(aurelia: Aurelia) {
aurelia.use
.standardConfiguration()
.plugin(PLATFORM.moduleName('aurelia-dialog'))
//.feature(PLATFORM.moduleName('resources/index'))
//.plugin(PLATFORM.moduleName('aurelia-ui-virtualization'))
.globalResources(
[
//Converters
PLATFORM.moduleName('converters/decimal-format'),
PLATFORM.moduleName('converters/unit-selection-format'),
PLATFORM.moduleName('converters/sort'),
PLATFORM.moduleName('converters/date-format'),
//Custom Element Registrations
//base-level components (standalone)
//PLATFORM.moduleName('components/custom-elements/table-cell-text-element'),
PLATFORM.moduleName('components/custom-elements/text-div-element'),
PLATFORM.moduleName('components/custom-elements/icon-button-element'),
PLATFORM.moduleName('components/custom-elements/checkbox-div-element'),
PLATFORM.moduleName('components/custom-elements/range-selector-element'),
PLATFORM.moduleName('components/custom-elements/unit-selector-element'),
//mid-level components (groupings/dependent on others)
PLATFORM.moduleName('components/custom-elements/content-header-element'),
PLATFORM.moduleName('components/custom-elements/table-configurable-element'),
PLATFORM.moduleName('components/custom-elements/table-tiered-element'),
PLATFORM.moduleName('components/custom-elements/grid-selector-element'),
//high-level components (groups of mid-level)
PLATFORM.moduleName('components/custom-elements/grid-selector-group-element'),
PLATFORM.moduleName('components/custom-elements/dropdown-select-element'),
PLATFORM.moduleName('components/custom-elements/alert-element'),
//Rate Components
PLATFORM.moduleName('components/custom-elements/base-charge-element'),
PLATFORM.moduleName('components/custom-elements/tiered-rate-element'),
PLATFORM.moduleName('components/custom-elements/tiered-per-unit-charge-element'),
PLATFORM.moduleName('components/custom-elements/rate-component-element'),
PLATFORM.moduleName('components/custom-elements/meter-charge-element')
]);
// Uncomment the line below to enable animation.
// aurelia.use.plugin(PLATFORM.moduleName('aurelia-animator-css'));
// if the css animator is enabled, add swap-order="after" to all router-view elements
// Anyone wanting to use HTMLImports to load views, will need to install the following plugin.
// aurelia.use.plugin(PLATFORM.moduleName('aurelia-html-import-template-loader'));
if (environment.debug) {
aurelia.use.developmentLogging();
}
if (environment.testing) {
aurelia.use.plugin(PLATFORM.moduleName('aurelia-testing'));
}
aurelia.start().then(() => {aurelia.setRoot(PLATFORM.moduleName('app'))});
}
which, I'm fairly sure, has nothing wrong in it - because it was working fine at the end of last week and hasn't changed since.
one noteworthy thing is that we altered the ModuleDependenciesPlugin section in our webpack.config.js. We added an entry: "aurelia-dialog": ['./aurelia-dialog', './ux-dialog-header', './ux-dialog-body', -dialog-footer', './attach-focus'] which was necessary to get the custom components from aurelia-dialog to load (see below).
This change didn't break the app initially. It was working fine for about a week, I'd say?
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const project = require('./aurelia_project/aurelia.json');
const { AureliaPlugin, ModuleDependenciesPlugin } = require('aurelia-webpack-plugin');
const { ProvidePlugin } = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
// config helpers:
const ensureArray = (config) => config && (Array.isArray(config) ? config : [config]) || [];
const when = (condition, config, negativeConfig) =>
condition ? ensureArray(config) : ensureArray(negativeConfig);
// primary config:
const title = 'Aurelia Navigation Skeleton';
const outDir = path.resolve(__dirname, 'wwwroot/dist');
const srcDir = path.resolve(__dirname, 'src');
const nodeModulesDir = path.resolve(__dirname, 'node_modules');
const baseUrl = '/';
const cssRules = [
{ loader: 'css-loader' },
];
module.exports = ({production, server, extractCss, coverage, analyze} = {}) => ({
resolve: {
extensions: ['.ts', '.js'],
modules: [srcDir, 'node_modules'],
},
entry: {
app: ['aurelia-bootstrapper'],
vendor: ['bluebird'],
},
mode: production ? 'production' : 'development',
output: {
path: outDir,
publicPath: baseUrl,
filename: production ? '[name].[chunkhash].bundle.js' : '[name].bundle.js',
sourceMapFilename: production ? '[name].[chunkhash].bundle.map' : '[name].bundle.map',
chunkFilename: production ? '[name].[chunkhash].chunk.js' : '[name].chunk.js'
},
performance: { hints: false },
devServer: {
contentBase: outDir,
// serve index.html for all 404 (required for push-state)
historyApiFallback: true
},
devtool: 'source-map',
module: {
rules: [
// CSS required in JS/TS files should use the style-loader that auto-injects it into the website
// only when the issuer is a .js/.ts file, so the loaders are not applied inside html templates
{
test: /\.css$/i,
issuer: [{ not: [{ test: /\.html$/i }] }],
use: extractCss ? ExtractTextPlugin.extract({
fallback: 'style-loader',
use: cssRules
}) : ['style-loader', ...cssRules],
},
{
test: /\.css$/i,
issuer: [{ test: /\.html$/i }],
// CSS required in templates cannot be extracted safely
// because Aurelia would try to require it again in runtime
use: cssRules
},
{test: /\.js\.map$/, loader: 'ignore-loader' },
{test: /\.ts\.orig$/, loader: 'ignore-loader' },
{test: /\.html\.orig$/, loader: 'ignore-loader' },
{test: /\.tst$/, loader: 'ignore-loader' },
{ test: /\.html$/i, loader: 'html-loader' },
{ test: /\.tsx?$/, loader: "ts-loader" },
//{ test: /\.json$/i, loader: 'json-loader' },
// use Bluebird as the global Promise implementation:
{ test: /[\/\\]node_modules[\/\\]bluebird[\/\\].+\.js$/, loader: 'expose-loader?Promise' },
// embed small images and fonts as Data Urls and larger ones as files:
{ test: /\.(png|gif|jpg|cur)$/i, loader: 'url-loader', options: { limit: 8192 } },
{ test: /\.woff2(\?v=[0-9]\.[0-9]\.[0-9])?$/i, loader: 'url-loader', options: { limit: 10000, mimetype: 'application/font-woff2' } },
{ test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/i, loader: 'url-loader', options: { limit: 10000, mimetype: 'application/font-woff' } },
// load these fonts normally, as files:
{ test: /\.(ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/i, loader: 'file-loader' },
...when(coverage, {
test: /\.[jt]s$/i, loader: 'istanbul-instrumenter-loader',
include: srcDir, exclude: [/\.{spec,test}\.[jt]s$/i],
enforce: 'post', options: { esModules: true },
})
]
},
plugins: [
//new AureliaWebpackPlugin({
// includeSubModules: [{
// moduleId: 'aurelia-dialog'
// },
// ],
// contextMap: {
// 'aurelia-dialog': 'node_modules/aurelia-dialog/dist/commonjs/aurelia-dialog.js'
// }
//}),
new AureliaPlugin({includeAll: "src"}),
new ProvidePlugin({
'Promise': 'bluebird'
}),
new ModuleDependenciesPlugin({
'aurelia-testing': ['./compile-spy', './view-spy'],
"aurelia-dialog": ['./aurelia-dialog', './ux-dialog-header', './ux-dialog-body',
'./ux-dialog-footer', './attach-focus']
}),
new HtmlWebpackPlugin({
template: 'index.ejs',
minify: production ? {
removeComments: true,
collapseWhitespace: true
} : undefined,
metadata: {
// available in index.ejs //
title, server, baseUrl
}
}),
...when(extractCss, new ExtractTextPlugin({
filename: production ? '[contenthash].css' : '[id].css',
allChunks: true
})),
...when(production, new CopyWebpackPlugin([
{ from: 'static/favicon.ico', to: 'favicon.ico' }])),
...when(analyze, new BundleAnalyzerPlugin())
]
});
package.json
{
"name": "webui",
"description": "An Aurelia client application.",
"version": "0.1.0",
"repository": {
"type": "???",
"url": "???"
},
"license": "MIT",
"dependencies": {
"#types/plotly.js": "^1.38.3",
"aurelia-animator-css": "^1.0.4",
"aurelia-bootstrapper": "^2.2.0",
"aurelia-dialog": "^1.1.0",
"aurelia-polyfills": "^1.3.0",
"bluebird": "^3.5.1",
"core-decorators": "^0.2.0",
"lit-html": "^1.0.0"
},
"peerDependencies": {},
"devDependencies": {
"#types/bootstrap": "^4.1.2",
"#types/jest": "^22.2.0",
"#types/lodash": "^4.14.105",
"#types/node": "^9.6.23",
"#types/pikaday": "^1.6.3",
"#types/webpack": "^4.1.1",
"ajv": "^6.0.0",
"aspnet-webpack": "^2.0.3",
"aurelia-cli": "^0.35.1",
"aurelia-loader-nodejs": "^1.0.1",
"aurelia-pal-nodejs": "^1.0.0-beta.3.2.0",
"aurelia-protractor-plugin": "^1.0.6",
"aurelia-testing": "^1.0.0-beta.4.0.0",
"aurelia-tools": "^2.0.0",
"aurelia-webpack-plugin": "^3.0.0-rc.1",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.5.1",
"core-js": "^2.5.7",
"css-loader": "^0.28.11",
"cypress": "^3.1.0",
"d3": "^5.1.0",
"del": "^3.0.0",
"dropzone": "^5.4.0",
"expose-loader": "^0.7.5",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.11",
"gulp": "4.0",
"gulp-rename": "^1.2.2",
"gulp-util": "^3.0.8",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.0.6",
"ignore-loader": "^0.1.2",
"intro.js": "^2.9.3",
"istanbul-instrumenter-loader": "^3.0.0",
"iterall": "^1.2.2",
"jest": "^22.4.2",
"jest-cli": "^23.0.0-alpha.0",
"jquery": "^3.3.1",
"jquery-sparkline": "^2.4.0",
"json-loader": "^0.5.7",
"minimatch": "^3.0.4",
"nouislider": "^11.1.0",
"nps": "^5.8.2",
"nps-utils": "^1.5.0",
"numeral": "^2.0.6",
"opn": "^5.3.0",
"pikaday": "^1.7.0",
"plotly.js": "^1.44.2",
"protractor": "^5.3.0",
"style-loader": "^0.20.3",
"through2": "^2.0.3",
"tinymce": "^4.7.11",
"ts-jest": "^22.4.1",
"ts-loader": "^4.0.1",
"ts-node": "^5.0.1",
"typescript": "^2.7.2",
"uglify-js": "^3.3.15",
"url-loader": "^1.0.1",
"vinyl-fs": "^3.0.2",
"wait-on": "^2.1.0",
"webpack": "^4.29.3",
"webpack-bundle-analyzer": "latest",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.1.14",
"webpack-hot-middleware": "^2.21.2",
"wnumb": "^1.1.0",
"wormhole.js": "^0.10.1"
},
"jest": {
"modulePaths": [
"<rootDir>/src",
"<rootDir>/node_modules"
],
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"transform": {
"^.+\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "\\.spec\\.(ts|js)x?$",
"setupFiles": [
"<rootDir>/test/jest-pretest.ts"
],
"testEnvironment": "node",
"collectCoverage": true,
"collectCoverageFrom": [
"src/**/*.{js,ts}",
"!**/*.spec.{js,ts}",
"!**/node_modules/**",
"!**/test/**"
],
"coverageDirectory": "<rootDir>/test/coverage-jest",
"coverageReporters": [
"json",
"lcov",
"text",
"html"
]
},
"engines": {
"node": ">= 6.0.0"
},
"scripts": {
"build": "webpack",
"start": "nps",
"test": "nps test",
"webpack-watch": "webpack --watch --info-verbosity verbose",
"webpack-display-errors": "webpack --display-error-details",
"compile": "tsc -w",
"compile-tests": "tsc -p cypress -w"
},
"main": "dist/app.bundle.js",
"-vs-binding": {
"ProjectOpened": [
"compile-tests",
"compile",
"webpack-watch"
]
}
}
aurelia.json
"name": "WebUIFinal",
"type": "project:application",
"bundler": {
"id": "webpack",
"displayName": "Webpack"
},
"build": {
"options": {
"server": "dev",
"extractCss": "prod",
"coverage": false
}
},
"platform": {
"id": "aspnetcore",
"displayName": "ASP.NET Core",
"port": 8080,
"hmr": false,
"open": false,
"output": "wwwroot/dist"
},
"loader": {
"id": "none",
"displayName": "None"
},
"transpiler": {
"id": "typescript",
"displayName": "TypeScript",
"fileExtension": ".ts"
},
"markupProcessor": {
"id": "minimum",
"displayName": "Minimal Minification",
"fileExtension": ".html"
},
"cssProcessor": {
"id": "none",
"displayName": "None",
"fileExtension": ".css"
},
"editor": {
"id": "none",
"displayName": "None"
},
"unitTestRunner": [
{
"id": "jest",
"displayName": "Jest"
}
],
"integrationTestRunner": {
"id": "protractor",
"displayName": "Protractor"
},
"paths": {
"root": "src",
"resources": "resources",
"elements": "resources/elements",
"attributes": "resources/attributes",
"valueConverters": "resources/value-converters",
"bindingBehaviors": "resources/binding-behaviors"
},
"testFramework": {
"id": "jasmine",
"displayName": "Jasmine"
}
}
My coworker and I have both spent the past couple days on this trying to get it figured out - so any help is appreciated.
I've tried resetting all the changes (including going back to before aurelia-dialog was added), have tried changing the aurelia-app attribute's value. Cleaned & rebuilt a few times. Restarted the computed. Re-cloned the repository....
The directory structure is
WebUIFinal/
├── wwwroot/
│ └── dist/
│ ├── index.html
│ ├── 0.chunk.js
│ ├── ...
│ ├── vendor.bundle.js
│ └── app.bundle.js
├── aurelia-project/
│ └── aurelia.json
├── src/
│ ├── app.ts
│ └── main.ts
├── package.json
└── webpack.config.js
(plus a bunch of other stuff, of course -- this is just what I deemed relevant)
EDIT:
After a debugging session, the issue with module with ID: main not found was simply resolved by changing Webpack AureliaPlugin to its simplest form:
plugins: [
new AureliaPlugin()
]
As the built code is in a format that Webpack can understand easily, no need for any configuration.
Also, it'd be easier for debugging. if configure function in main is wrapped in a try catch, or catch(ex =>) of promise, so you can see any issues coming up, instead of a silently fail and a forever loading screen.
With the latest release of dialog, you should not have to manually include ModuleDependenciesPlugin for dialog anymore, as it uses dynamic import API, which is understood by Webpack naturally. So I would suggest going back to your original one, and delete that configuration.
new ModuleDependenciesPlugin({
'aurelia-testing': ['./compile-spy', './view-spy'],
// "aurelia-dialog": ['./aurelia-dialog', './ux-dialog-header', './ux-dialog-body', './ux-dialog-footer', './attach-focus']
})
Related
I'm new to webpack and am trying to make a webpack configuration that generates source maps so I can debug my JS and JSX code in the browser.
The build is actually successful so far, except that no source maps are generated. I've been researching for a long time and tried many solutions, including several ones from StackOverflow. But nothing works for me.
Below I am posting my current files in the hope that someone can help me. Thanks in advance for helping.
Root directory after build:
- webpack.config.js
- package.json
- package-lock.json
- node_modules
- dist
|- bundle.js
|- bundle.js.map
|- index.html
|- main.min.js
|- main.min.js.map
|- node_modules
- src
|- index.html
|- index.js
|- helper.jsx //My own jsx file
What my webpack app looks like in the browser:
webpack.config.js:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports =
{
entry: path.join(__dirname, "src", "index.js"),
mode: 'development',
devtool: 'source-map',
output:
{
path: path.resolve(__dirname, "dist"),
filename: "[name].min.js"
},
module:
{
rules:
[
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use:
{
loader: "babel-loader",
options:
{
presets:
[
'#babel/preset-env',
'#babel/preset-react'
]
}
}
},
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.(png|jp(e*)g|gif)$/,
use: ['file-loader'],
},
]
},
plugins:
[
new HtmlWebpackPlugin
(
{
template: path.join(__dirname, "src", "index.html"),
hash: true
}
),
],
}
package.json:
{
"name": "frontend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"dev": "webpack serve"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"#babel/core": "^7.20.12",
"#babel/preset-env": "^7.20.2",
"#babel/preset-react": "^7.18.6",
"babel-loader": "^9.1.2",
"html-webpack-plugin": "^5.5.0",
"source-map-loader": "^4.0.1",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.11.1"
}
}
I have set up Webpack and want to make it usable for almost anything you can imagine. But when I want to implement jest for testing it gives me an error on Babel.
My webpack.config.js
const path = require("path");
const ReactRefreshWebpackPlugin = require("#pmmmwh/react-refresh-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
let mode = "development";
let target = "web";
const plugins = [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
];
if (process.env.NODE_ENV === "production") {
mode = "production";
// Temporary workaround for 'browserslist' bug that is being patched in the near future
target = "browserslist";
}
if (process.env.SERVE) {
// We only want React Hot Reloading in serve mode
plugins.push(new ReactRefreshWebpackPlugin());
}
module.exports = {
// mode defaults to 'production' if not set
mode: mode,
// This is unnecessary in Webpack 5, because it's the default.
// However, react-refresh-webpack-plugin can't find the entry without it.
entry: "./src/index.js",
output: {
// output path is required for `clean-webpack-plugin`
path: path.resolve(__dirname, "dist"),
// this places all images processed in an image folder
assetModuleFilename: "images/[hash][ext][query]",
},
module: {
rules: [
{
test: /\.(s[ac]|c)ss$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
// This is required for asset imports in CSS, such as url()
options: { publicPath: "" },
},
"css-loader",
"postcss-loader",
// according to the docs, sass-loader should be at the bottom, which
// loads it first to avoid prefixes in your sourcemaps and other issues.
"sass-loader",
],
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
/**
* The `type` setting replaces the need for "url-loader"
* and "file-loader" in Webpack 5.
*
* setting `type` to "asset" will automatically pick between
* outputing images to a file, or inlining them in the bundle as base64
* with a default max inline size of 8kb
*/
type: "asset",
/**
* If you want to inline larger images, you can set
* a custom `maxSize` for inline like so:
*/
// parser: {
// dataUrlCondition: {
// maxSize: 30 * 1024,
// },
// },
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
// without additional settings, this will reference .babelrc
loader: "babel-loader",
options: {
/**
* From the docs: When set, the given directory will be used
* to cache the results of the loader. Future webpack builds
* will attempt to read from the cache to avoid needing to run
* the potentially expensive Babel recompilation process on each run.
*/
cacheDirectory: true,
},
},
},
],
},
plugins: plugins,
target: target,
devtool: "source-map",
resolve: {
extensions: [".js", ".jsx"],
},
// required if using webpack-dev-server
devServer: {
contentBase: "./dist",
hot: true,
},
};
And the package.json
{
"name": "webpack-starters",
"version": "1.0.0",
"private": true,
"description": "A collection of different Webpack setups for quick referencing or starting from",
"scripts": {
"start": "cross-env SERVE=true webpack serve",
"watch": "webpack --watch",
"build": "cross-env NODE_ENV=production webpack",
"build-dev": "webpack",
"clean": "rm -rf ./dist",
"test": "jest --coverage"
},
"author": "Mike van Eckendonk",
"license": "MIT",
"devDependencies": {
"#babel/core": "^7.16.5",
"#babel/preset-env": "^7.16.5",
"#babel/preset-react": "^7.16.5",
"#pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
"babel": "^6.23.0",
"babel-jest": "^27.4.5",
"babel-loader": "^8.2.3",
"clean-webpack-plugin": "^3.0.0",
"cross-env": "^7.0.3",
"css-loader": "^5.2.7",
"html-webpack-plugin": "^5.5.0",
"jest-webpack": "^0.3.1",
"mini-css-extract-plugin": "^2.1.0",
"postcss": "^8.4.4",
"postcss-loader": "^4.3.0",
"postcss-preset-env": "^6.7.0",
"react-refresh": "^0.9.0",
"sass": "^1.44.0",
"sass-loader": "^10.2.0",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.7.1"
},
"dependencies": {
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
}
babel.config.js
// Cannot load "react-refresh/babel" in production
const plugins = [];
if (process.env.NODE_ENV !== "production") {
plugins.push("react-refresh/babel");
}
module.exports = {
presets: [
"#babel/preset-env",
// Runtime automatic with React 17+ allows not importing React
// in files only using JSX (no state or React methods)
["#babel/preset-react", { runtime: "automatic" }],
],
plugins: plugins,
};
Does anyone have an idea of how to solve these errors? The test files don't have an error, because without Webpack they are correct.
Either remove react-refresh/babel from babel config for test environment or just change the if condition and it should work.
if (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test") {...}
Edit: Updated the if to use and instead of or
I'm new to webpack so sorry if this is something obvious. I'm trying to get the package antlr4-webpack-loader to work, generating some source code from a .g4 file. I think I'm most of the way there, as I have a javascript file with require in it, and the .bundle. file seems to contain the output of antlr4, however it also has this:
module.exports = __webpack_require__(!(function webpackMissingModule() { var e = new Error("Cannot find module 'antlr4/index'"); e.code = 'MODULE_NOT_FOUND'; throw e; }()));
contentScript.js starts as below:
import 'jquery';
import 'antlr4'; // This line doesn't cause the error
import '../anaplan/AnaplanFormula.g4'; // This line causes the MODULE_NOT_FOUND error
webpack.config.js as below:
var webpack = require("webpack"),
path = require("path"),
fileSystem = require("fs"),
env = require("./utils/env"),
CleanWebpackPlugin = require("clean-webpack-plugin").CleanWebpackPlugin,
CopyWebpackPlugin = require("copy-webpack-plugin"),
HtmlWebpackPlugin = require("html-webpack-plugin"),
WriteFilePlugin = require("write-file-webpack-plugin");
var options = {
mode: process.env.NODE_ENV || "development",
entry: {
contentScript: path.join(__dirname, "src", "js", "contentScript.js"),
background: path.join(__dirname, "src", "js", "background.js"),
},
output: {
path: path.join(__dirname, "build"),
filename: "[name].bundle.js"
},
module: {
rules: [
{
test: /\.css$/,
loader: "style-loader!css-loader",
exclude: /node_modules/
},
{
test: new RegExp('.(jpg|jpeg|png|gif|eot|otf|svg|ttf|woff|woff2)$'),
loader: "file-loader?name=[name].[ext]",
exclude: /node_modules/
},
{
test: /\.html$/,
loader: "html-loader",
exclude: /node_modules/
},
{
test: /\.g4/,
exclude: /(node_modules)/,
use: {
loader:'antlr4-webpack-loader'
}
}
]
},
resolve: {
modules: [path.resolve(__dirname, 'src'), 'node_modules']
},
node: { module: "empty", net: "empty", fs: "empty" },
plugins: [
// clean the build folder
new CleanWebpackPlugin(),
// expose and write the allowed env vars on the compiled bundle
new webpack.EnvironmentPlugin(["NODE_ENV"]),
new CopyWebpackPlugin([{
from: "src/manifest.json",
transform: function (content, path) {
// generates the manifest file using the package.json informations
return Buffer.from(JSON.stringify({
description: process.env.npm_package_description,
version: process.env.npm_package_version,
...JSON.parse(content.toString())
}))
}
}]),
new WriteFilePlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
]
};
if (env.NODE_ENV === "development") {
options.devtool = "cheap-module-source-map";
}
module.exports = options;
From what I can tell the antlr4-webpack-loader plugin spawns a new webpack process for just the .g4 file and generates a bundle.js file from that as it's output, which then gets bundled into the 'parent' file. I can step through the code within antlr4-webpack-loader and that does appear to work (like I say, the output from it appears to be within my contentScript.bundle.js file. I can see it as something about externals: [ 'antlr4/index' ], which I guess is because the files it generates from the .g4 file require it, but the reference should get resolved by the script that required the g4.
For reference, package.json below which doesn't include the antlr4 package in devDependencies, however I get the same error when i include it in both devDependencies and dependencies:
{
"name": "anaplanextension",
"version": "1.0.0",
"description": "",
"main": "background.js",
"directories": {
"lib": "lib"
},
"dependencies": {
"antlr4": "^4.9.2",
"arrive": "^2.4.1",
"jquery": "^3.6.0"
},
"devDependencies": {
"antlr4-webpack-loader": "^0.1.1",
"clean-webpack-plugin": "3.0.0",
"copy-webpack-plugin": "5.0.5",
"css-loader": "3.2.0",
"file-loader": "4.3.0",
"fs-extra": "8.1.0",
"html-loader": "0.5.5",
"html-webpack-plugin": "3.2.0",
"style-loader": "1.0.0",
"webpack": "4.41.2",
"webpack-cli": "3.3.10",
"webpack-dev-server": "3.9.0",
"write-file-webpack-plugin": "4.5.1"
},
"scripts": {
"build": "node utils/build.js",
"start": "node utils/webserver.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/georgeduckett/AnaplanExtension.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/georgeduckett/AnaplanExtension/issues"
},
"homepage": "https://github.com/georgeduckett/AnaplanExtension#readme"
}
I recommend to go a different route here. That webpack loader has not been updated in the last 4 years, uses a pretty old ANTLR4 jar (current version is 4.9.2) and uses the Javascript runtime, which is known for certain problems.
Instead I recommend that you switch to the antlr4ts runtime and use antlr4ts-cli to generate your files from the grammar. Both are still marked as being alpha, but I have used these packages for years already (e.g. in my vscode extension vscode-antlr4).
With that in place you can remove the webpack loader and generate the parser/lexer files as part of your build process.
We have an application (a website) with some React components, css and js compiled with webpack.
Our workflow is to npm run start in the /src/ folder while developing locally, which generates CSS and JS files in /dist/ then run npm run build to clear down refresh all the files in the /dist/ folder before deploying to live. That is the intent, anyway.
The problem is, when we deploy a change to the live environment, it seems the browser still has previous versions of the CSS/JS files cached, or not reading correctly from the new versions. This only happens with the hashed/chunked (React component) files (see ** in file structure below), not the main.js or main.scss file.
We thought webpack produced new 'chunks'/files with each build. Is there a way we can force webpack to do this so the files are read as new when they change, or the filenames are different? I do want the files to be cached by the browser, but I also want new changes to be accounted for.
Example File Structure
--/src/
----/scss/
------main.scss
----/js/
------main.js (imports js components)
------/components/
--------banner.js
--------ReactComponent.jsx (imports ReactComponent.scss)
--------ReactComponent.scss
--/dist/
----/css/
------main.css
------2.css (react component css) (**)
------6.css (react component css) (**)
----/js/
------main.js
------0_39cd0323ec029f4edc2f.js (react component js) (**)
------1_c03b31c54dc165cb590e.js (react component js) (**)
** these are the files that seem to get cached or not read properly when changes are made.
webpack.config.js
const webpack = require("webpack");
const path = require("path");
const autoprefixer = require("autoprefixer");
const TerserJSPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
module.exports = {
entry: {
main: ["./js/main.js", "./scss/main.scss"],
},
output: {
filename: "js/[name].js",
chunkFilename: "js/[name]_[chunkhash].js",
path: path.resolve(__dirname, "../dist/"),
publicPath: "/app/themes/[package]/dist/",
jsonpFunction: "o3iv79tz90732goag"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(sass|scss|css)$/,
exclude: "/node_modules/",
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
importLoaders: 2,
sourceMap: true
}
},
{
loader: "postcss-loader",
options: {
plugins: () => [require("precss"), require("autoprefixer")],
sourceMap: true
}
},
{
loader: "sass-loader",
options: {
sourceMap: true,
includePaths: [path.resolve(__dirname, "../src/scss")]
}
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ["file-loader"]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ["file-loader"]
}
]
},
optimization: {
minimizer: [
new TerserJSPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
safe: true,
zindex: false,
discardComments: {
removeAll: true
}
},
canPrint: true
})
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
chunkFilename: "css/[id].css"
})
]
};
package.json
{
"name": "packagename",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "(rm -rf ./../dist/*) & webpack --mode production",
"start": "webpack --mode development --watch "
},
"keywords": [],
"author": "Sarah",
"license": "ISC",
"browserslist": [
"last 4 versions"
],
"devDependencies": {
"#babel/core": "^7.9.0",
"#babel/plugin-proposal-object-rest-spread": "^7.9.5",
"#babel/plugin-syntax-dynamic-import": "^7.8.3",
"#babel/plugin-transform-arrow-functions": "^7.2.0",
"#babel/plugin-transform-classes": "^7.9.5",
"#babel/plugin-transform-flow-strip-types": "^7.9.0",
"#babel/plugin-transform-react-jsx": "^7.9.4",
"#babel/preset-env": "^7.9.5",
"#babel/preset-flow": "^7.9.0",
"#babel/preset-react": "^7.0.0",
"autoprefixer": "^7.1.1",
"babel-loader": "^8.1.0",
"babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
"babel-preset-env": "^1.7.0",
"browser-sync": "^2.26.7",
"browser-sync-webpack-plugin": "^2.2",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^3.5.3",
"cssnano": "^4.1.10",
"mini-css-extract-plugin": "^0.8.2",
"node-sass": "^4.14.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^2.0.5",
"precss": "^4.0.0",
"resolve-url-loader": "^2.0.2",
"sass-loader": "^6.0.5",
"terser-webpack-plugin": "^2.3.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
},
"dependencies": {
"axios": "^0.19.2",
"body-scroll-lock": "^2.7.1",
"can-autoplay": "^3.0.0",
"debounce": "^1.0.2",
"file-loader": "^5.1.0",
"lazysizes": "^4.1.8",
"moment": "^2.24.0",
"objectFitPolyfill": "^2.3.0",
"promise-polyfill": "^8.1.3",
"react": "^16.9.0",
"react-content-loader": "^5.0.4",
"react-device-detect": "^1.12.1",
"react-dom": "^16.9.0",
"react-html-parser": "^2.0.2",
"react-intersection-observer": "^8.26.2",
"react-moment": "^0.9.7",
"react-pdf": "^4.1.0",
"scrollmonitor": "^1.2.4",
"socket.io": "^2.3.0"
}
}
In order to bust a cache on a build, you need to change the url of static asset (js / css).
The best way to do so is to generate random string based on content of the file (called hash), the benefit of this approach is that if the final file didn't changed between deploys it will generate the same hash => clients will use the cached file. If it does changed => hash changed => file name change => clients will fetch a new file.
Webpack has a built it method for this.
// webpack.config.js
module.exports = {
entry: {
main: ["./js/main.js", "./scss/main.scss"],
},
output: {
filename: process.env.NODE_ENV === 'production'? "js/[name]-[hash].js": "js/[name].js", // this will attach the hash of the asset to the filename when building for production
chunkFilename: "js/[name]_[chunkhash].js",
path: path.resolve(__dirname, "../dist/"),
publicPath: "/app/themes/[package]/dist/",
jsonpFunction: "o3iv79tz90732goag"
},
...
}
Edit:
In order to update your HTML file with the new filename (which now will contain hash) you can use HTMLWebpackPlugin which was created specifically for this purpose.
It supports custom template if you need to provide your own html, or creating one. Review the docs.
Just a small update over brilliant #felixmosh solution.
For Webpack 5.x I'm using this:
//webpack.prod.js
const webpackConfig = {
module: {
...
},
output: {
filename: '[name]-[contenthash].js',
chunkFilename: '[name]_[contenthash].js',
},
[contenthash] looks better then [hash] - contenthash only changes when the content of the asset actually changes. I wonder why this is not the default setting for Webpack ?
I love you guys #felixmosh #Sarah for figuring this out !
I have created a site using Angular 2. I started making my site using the Angular 2 QuickStart Guide as base and it's working like it should if I use the command npm start. Now that the site is finished I need to build/deploy (don't know the correct definition) to production so the site can be access to the client. The question is: how to I build this project for production? (without the need to run npm install)
The best thing I could found was to to try ng build -prod, but it says that my project is not a cli project. How to a generate the independent files to open just the index.htmlpage and access the site? Is it possible?
Update:
Maybe I was not clear: what I'm looking for is a way to get all the TypeScripts files and build it in a pure HTML/JavaScript/CSS site ready to display. No compression or minify needed at the moment. Is it possible? If not, what are other solutions (preferably independent on the host)?
So from what I understand from using Angular2 the last few weeks is what you're essentially creating is a client-side single page app so all you need to deliver is the HTML page with references to the respective JavaScript files.
I've been investigating WebPack for packaging an application (and still in the middle of getting it right), however, WebPack will combine all the compiled typescript files into a single (or multiple, still working on this part) Javascript files while also injecting the reference to the javascript files into your index.html page.
My current project compiles the typescript files (using gulp) using a web pack config to configure the output javascript file (main.ts -> main.js):
gulp.task("build-tsc", function() {
return gulp.src("entry.js")
.pipe(webpack( require("../../../webpack.config.js")))
.pipe(gulp.dest(config.dist));
});
My web pack.config.js looks like (the webpack module ignores the fact I don't have an entry.js):
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpack = require('webpack');
module.exports = {
entry: {
"main": "./src/app/main.ts",
"share": "./src/app/share_main.ts",
"polyfills": "./src/app/polyfills.ts"
},
output: {
path: __dirname,
filename: "[name].js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" },
{ test: /\.ts$/, loader: 'ts-loader' }
]
},
resolve: {
extensions: ['', '.js', '.ts']
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ['main', 'share', 'polyfills']
}),
new HtmlWebpackPlugin({
template: 'src/index.html'
})
]
};
My original codebase is:
src/
index.html
assets/
styles/
main.scss
app/
app.component.ts
app.routes.ts
app.module.ts
share_main.ts
polyfills.ts
dashboard/
dashboard.component.ts
dashboard.html
navbar/
navbar.component.ts
navbar.html
So what I end up with (post build) is a new dist/ directory with the files in place for use:
dist/
index.html
main.js
share.js
polyfill.js
app/
dashboard/
dashboard.html
navbar/
navbar.html
styles/
main.css
Right now I'm using browserSync for now to serve the files for dev purposes, but you theoretically should be able to serve them up as static content via NGINX, Apache or proxy them through NGINX/Apache to lite-server.
The idea behind WebPack is that you give it an entry point (in this case main.ts) and it crawls the import statements ensuring that anything it encounters is added to the resulting Javascript files then adds them to the index.html file automatically.
Like I mentioned I've got a working app but I'm trying to understand the "multiple entry points" better but the above should work just the same.
I'm really bad at dealing with webpack and wasn't able to Anthony Ikeda solution or any other solution I found on web. If anyone get stuck in this like me, my solution was to use Angular Cli. I create a new project with angular cli, create all the pages, components and services with angular cli and copied the code from the old no-cli project to this new cli project. With a cli project, I used the ng build command to build the project and get the files to deploy.
I'm using this solution and it works perfectly for me (only html + css + js files) ... only minification give me some problems.
My webpack.config.js:
/// <binding />
var environment = (process.env.NODE_ENV || "development").trim();
if (environment === "development") {
module.exports = require('./webpack.dev.js');
} else {
module.exports = require('./webpack.prod.js');
}
My webpack.dev.js
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var webpack = require("webpack");
var HtmlWebpackPlugin = require("html-webpack-plugin");
var CleanWebpackPlugin = require('clean-webpack-plugin');
var path = require('path');
module.exports = {
entry: {
"polyfills": "./polyfills.ts",
"vendor": "./vendor.ts",
"app": "./app/main.ts",
},
resolve: {
extensions: ['', '.ts', '.js', '.json', '.css', '.scss', '.html']
},
output: {
path: "./app_build",
filename: "js/[name]-[hash:8].bundle.js"
},
devtool: 'source-map',
module: {
loaders: [
{
loader: "babel-loader",
// Skip any files outside of your project's `src` directory
//include: [
// "app_build",
//],
exclude: [
path.resolve(__dirname, "node_modules")
],
// Only run `.js` and `.jsx` files through Babel
test: /\.js/,
// Options to configure babel with
query: {
plugins: ['transform-runtime', 'babel-plugin-transform-async-to-generator'],
presets: ['es2015', 'stage-0'],
}
},
{
test: /\.ts$/,
loader: "ts"
},
{
test: /\.html$/,
loader: "html"
},
//{
// test: /\.(png|jpg|gif|ico|woff|woff2|ttf|svg|eot)$/,
// loader: "file?name=assets/[name]-[hash:6].[ext]",
//},
{
test: /\.(png|jpg|gif|ico)$/,
//include: path.resolve(__dirname, "assets/img"),
loader: 'file?name=/assets/img/[name]-[hash:6].[ext]'
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
// exclude: /node_modules/,
loader: 'file?name=/assets/fonts/[name].[ext]'
},
// Load css files which are required in vendor.ts
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css!sass')
},
]
},
plugins: [
new ExtractTextPlugin("css/[name]-[hash:8].bundle.css", { allChunks: true }),
new webpack.optimize.CommonsChunkPlugin({
name: ["app", "vendor", "polyfills"]
}),
new CleanWebpackPlugin(
[
"./app_build/js/",
"./app_build/css/",
"./app_build/assets/",
"./app_build/index.html"
]
),
// inject in index.html
new HtmlWebpackPlugin({
template: "./index.html",
inject: "body"
}),
new webpack.ProvidePlugin({
jQuery: 'jquery',
$: 'jquery',
jquery: 'jquery'
})
],
devServer: {
//contentBase: path.resolve(__dirname, "app_build/"),
historyApiFallback: true,
stats: "minimal"
}
};
My webpack.prod.js:
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var webpack = require("webpack");
var HtmlWebpackPlugin = require("html-webpack-plugin");
var CleanWebpackPlugin = require('clean-webpack-plugin');
var path = require('path');
var BabiliPlugin = require("babili-webpack-plugin");
module.exports = {
entry: {
"polyfills": "./polyfills.ts",
"vendor": "./vendor.ts",
"app": "./app/main.ts"
},
resolve: {
extensions: ['', '.ts', '.js', '.json', '.css', '.scss', '.html']
},
output: {
path: "./app_build",
filename: "js/[name]-[hash:8].bundle.min.js"
},
module: {
loaders: [
{
loader: "babel-loader",
// Skip any files outside of your project's `src` directory
//include: [
// "app_build",
//],
exclude: [
path.resolve(__dirname, "node_modules")
],
// Only run `.js` and `.jsx` files through Babel
test: /\.js/,
// Options to configure babel with
query: {
plugins: ['transform-runtime', 'babel-plugin-transform-async-to-generator'],
presets: ['es2015', 'stage-0'],
}
},
{
test: /\.ts$/,
loader: "ts"
},
{
test: /\.html$/,
loader: "html"
},
//{
// test: /\.(png|jpg|gif|ico|woff|woff2|ttf|svg|eot)$/,
// loader: "file?name=assets/[name]-[hash:6].[ext]",
//},
{
test: /\.(png|jpg|gif|ico)$/,
//include: path.resolve(__dirname, "assets/img"),
loader: 'file?name=assets/img/[name]-[hash:6].[ext]'
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
// exclude: /node_modules/,
loader: 'file?name=/assets/fonts/[name].[ext]'
},
// Load css files which are required in vendor.ts
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('css!sass')
},
]
},
plugins: [
new ExtractTextPlugin("css/[name]-[hash:8].bundle.css", { allChunks: true }),
new webpack.optimize.CommonsChunkPlugin({
name: ["app", "vendor", "polyfills"]
}),
new CleanWebpackPlugin(
[
"./app_build/js/",
"./app_build/css/",
"./app_build/assets/",
"./app_build/index.html"
]
),
// inject in index.html
new HtmlWebpackPlugin({
template: "./index.html",
inject: "body"
}),
new BabiliPlugin({ comments: false }),
new webpack.ProvidePlugin({
jQuery: 'jquery',
$: 'jquery',
jquery: 'jquery'
})
],
devServer: {
historyApiFallback: true,
stats: "minimal"
}
};
and then my package.json (with command to build for prod):
{
"name": "dipendentistatali",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"start": "tsc && npm install && npm run build",
"watch": "SET NODE_ENV=development && webpack --watch --color",
"test": "webpack-dev-server --inline --hot",
"build": "SET NODE_ENV=development && webpack -d --color",
"buildProduction": "SET NODE_ENV=production && webpack -d --color",
"lint": "tslint ./app/**/*.ts -t verbose",
"postinstall": "typings install",
"tsc": "tsc",
"tsc:w": "tsc -w",
"typings": "typings"
},
"keywords": [],
"author": "",
"dependencies": {
"#angular/common": "2.1.1",
"#angular/compiler": "2.1.1",
"#angular/core": "2.1.1",
"#angular/forms": "2.1.1",
"#angular/http": "2.1.1",
"#angular/platform-browser": "2.1.1",
"#angular/platform-browser-dynamic": "2.1.1",
"#angular/router": "3.0.0",
"#angular/upgrade": "2.0.0",
"#ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.15",
"angular2-cool-http": "^1.2.3",
"angular2-toaster": "^1.0.1",
"babel-plugin-transform-async-to-generator": "^6.16.0",
"bootstrap": "^3.3.6",
"core-js": "^2.4.1",
"jquery": "2.2.4",
"ng2-bs3-modal": "^0.10.4",
"ng2-modal": "0.0.22",
"ng2-resource-rest": "^1.5.3",
"ng2-slim-loading-bar": "^2.0.4",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.12",
"systemjs": "0.19.27",
"zone.js": "^0.6.23"
},
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-core": "^6.18.2",
"babel-loader": "^6.2.7",
"babel-plugin-transform-es2015-arrow-functions": "^6.8.0",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-preset-es2015": "^6.18.0",
"clean-webpack-plugin": "0.1.10",
"concurrently": "^2.2.0",
"css-loader": "^0.23.1",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"html-loader": "^0.4.3",
"html-webpack-plugin": "^2.15.0",
"lite-server": "^2.2.2",
"lodash": "^4.11.1",
"node-sass": "^3.13.0",
"raw-loader": "^0.5.1",
"rimraf": "^2.5.2",
"sass-loader": "^3.2.3",
"style-loader": "^0.13.1",
"ts-loader": "^0.8.1",
"tslint": "^3.7.4",
"typescript": "^2.0.2",
"typings": "^1.3.2",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2",
"webpack-merge": "^0.9.0",
"webpack-stream": "^3.2.0"
}
}
So if you launch npm start build it build the prod version in a directory that i called app_build/
Hope it can help you