Running webpack as child process to generate source files - javascript

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.

Related

Webpack with JavaScript, React and jest gives Babel Error

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

Webpack: Unable to find module with ID: main -- (Aurelia App)

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']
})

Webpack 4 and Uglify Plugin (TypeError: Cannot read property 'length' of undefined)

I'm having problems with Webpack 4 on a Linux machine. The build works fine in dev mode, but fail in production. It also seems to be working on a windows machine. I did try do downgrade webpack to an older version and nothing.
Nodejs:
v10.2.1
*TypeError: Cannot read property 'length' of undefined* at node_modules/uglifyjs-webpack-plugin/dist/uglify/index.js:59
this.workers = workers === true ? _os2.default.cpus().length - 1 : Math.min(Number(workers) || 0, _os2.default.cpus().length - 1);
packge.json
{
"name": "webpack-demo",
"version": "1.0.0",
"license": "MIT",
"scripts": {
"build": "webpack -p"
},
"devDependencies": {},
"dependencies": {
"#types/node": "^10.5.1",
"css-loader": "^0.28.11",
"global": "^4.3.2",
"node-sass": "^4.9.1",
"npm": "^6.1.0",
"sass-loader": "^7.0.3",
"style-loader": "^0.21.0",
"ts-loader": "^4.4.2",
"typescript": "^2.9.2",
"uglifyjs-webpack-plugin": "1.0.0-beta.2",
"webpack": "^4.15.1",
"webpack-cli": "^3.0.8"
}
}
webpack.config.js
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
var webpack = require('webpack');
module.exports = {
entry: './src/index.ts',
devtool: 'source-map',
mode: 'production',
module: {
rules: [{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
exclude: /node_modules/
}
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js','.css','.scss']
},
plugins: [
new UglifyJsPlugin()
],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
}
}
Setting mode to production in Webpack v4 should do enough optimisations, so there's no need to specifically require the Uglify plugin. Try remove uglifyjs-webpack-plugin and there's also no need for passing the -p flag for the build script.
If you want to customise the Uglify plugin, you can also do so in Webpack's optimization config, see https://webpack.js.org/configuration/optimization/
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
//...
optimization: {
minimizer: [
new UglifyJsPlugin({ /* your config */ })
]
}
};
Finally, I have a basic webpack v4 starter boilerplate with all the latest ecosystem on Github, take a look and see if it will help you or not

How can I build/deploy an angular 2 project to production?

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

React Js - how to keep bundle.min.js small?

I'm pretty new to React and javascript dev. I'm used to java build tools, so now using NPM i've got a new landscape of build tools to learn. I am just getting going into my project and I noticed that my minified, uglified bundle is still ~275kb and I'm wondering how this could scale to a large size app. My raw source code itself is only 34kb, but of course I have to pull in all those frameworks and whatnot.
So - how can I keep the size of my app small as my app grows? It's a bit hard for me to follow stuff I read online because many folks seem to be using Grunt, but i'm just using npm start and npm run build on the package below.
Should I be managing my requires() in different ways to prevent duplicate packaging? I'm not sure where to start...
Here's my package.json:
{
"name": "someapp",
"version": "0.0.1",
"description": "foo",
"repository": "",
"main": "js/app.js",
"dependencies": {
"classnames": "^2.1.3",
"flux": "^2.0.1",
"jquery": "^2.2.0",
"keymirror": "~0.1.0",
"object-assign": "^1.0.0",
"react": "^0.12.0"
},
"devDependencies": {
"browserify": "^6.2.0",
"envify": "^3.0.0",
"jest-cli": "^0.4.3",
"reactify": "^0.15.2",
"uglify-js": "~2.4.15",
"watchify": "^2.1.1"
},
"scripts": {
"start": "watchify -o js/bundle.js -v -d js/app.js",
"build": "browserify . -t [envify --NODE_ENV production] | uglifyjs -cm > js/bundle.min.js",
"test": "jest"
},
"author": "Some Guy",
"browserify": {
"transform": [
"reactify",
"envify"
]
},
"jest": {
"rootDir": "./js"
}
}
I was able to achieve pretty good results with Webpack. I wrote about this in Optimizing Webpack Prod Build for React + ES6 Apps
Here's my Webpack config:
var webpack = require('webpack');
var path = require('path');
var nodeEnv = process.env.NODE_ENV || 'development';
var isProd = nodeEnv === 'production';
module.exports = {
devtool: isProd ? 'cheap-module-source-map' : 'eval',
context: path.join(__dirname, './client'),
entry: {
jsx: './index.js',
html: './index.html',
vendor: ['react']
},
output: {
path: path.join(__dirname, './static'),
filename: 'bundle.js',
},
module: {
loaders: [
{
test: /\.html$/,
loader: 'file?name=[name].[ext]'
},
{
test: /\.css$/,
loaders: [
'style-loader',
'css-loader'
]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loaders: [
'react-hot',
'babel-loader'
]
},
],
},
resolve: {
extensions: ['', '.js', '.jsx'],
root: [
path.resolve('./client')
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: false
}),
new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify(nodeEnv) }
})
],
devServer: {
contentBase: './client',
hot: true
}
};
Two key points to consider:
devtool: isProd ? 'cheap-module-source-map' : 'eval',
This one will output minimal sourcemaps, and will use external files for that, which is good for your final bundle size.
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: false
}),
new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify(nodeEnv) }
})
],
Uglify - well you probably know what it does. Coupled with the process.env setting will weed out quite a bit of dev code from React lib.
CommonsChunkPlugin will allow you to bundle libraries (or other chunks per your liking) to separate build files. This is particularly awesome as it allows you to set up different caching patterns for vendor libraries. E.g. you can cache those more aggressively than your business logic files.
Oh, and if you care to see my package.json that matches this webpack config:
"scripts": {
"start": "webpack-dev-server --history-api-fallback --hot --inline --progress --colors --port 3000",
"build": "NODE_ENV=production webpack --progress --colors"
},
"devDependencies": {
"babel-core": "^6.3.26",
"babel-loader": "^6.2.0",
"babel-plugin-transform-runtime": "^6.3.13",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"file-loader": "^0.8.4",
"webpack": "^1.12.2",
"webpack-dev-server": "^1.12.0",
"webpack-hot-middleware": "^2.2.0"
}
Edit: Tree shaking is a shiny new version expected in Webpack 2 (currently in beta). Coupled with the config above, it will be a killer feature that will minify your final bundle significantly.
Edit 2: Webpack 2 I modified an existing sample app to use Webpack 2 config. It resulted in additional 28% savings. See the project here:Webpack 2 sample config project

Categories

Resources