Related
I expend almost 6 hours trying to make this work but it seems it refuses by all methods.
I made a simple API with NodeJS using Typescript and Webpack, but when I tried to debug it put break points and all of that stuff, VSCode put it very difficult.
Launch.json :
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"preLaunchTask": "npm: start - server",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\server\\webpack.config.ts",
"outFiles": [
"${workspaceFolder}/server/dist/index.js"
],
"sourceMaps": true,
"trace": true
}
]
}
webpack.config.ts :
const webpack = require("webpack");
const path = require("path");
const nodeExternals = require("webpack-node-externals");
module.exports = {
entry: ["./src/index.ts"],
devtool: "source-map",
watch: true,
target: "node",
externals: [
nodeExternals({
allowlist: ["webpack/hot/poll?100"]
})
],
module: {
rules: [
{
use: "ts-loader",
exclude: /node_modules/
}
]
},
mode: "development",
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
plugins: [new webpack.HotModuleReplacementPlugin()],
output: {
path: path.join(__dirname, "dist"),
filename: "index.js"
}
};
index.ts of my app which uses middleware with routers to redirect url requests.
import express from "express";
import cors from "cors";
import helmet from "helmet";
import { categoryRouter } from "./routers/category.router";
import { CategoryPostgre } from "./database/postgre/category.postgre";
dotenv.config();
/**
* App Variables
*/
if (!process.env.PORT) {
process.exit(1);
}
const PORT: number = parseInt(process.env.PORT as string, 10);
const app = express();
const router = express.Router();
/**
* App Configuration
*/
app.use(helmet());
app.use(cors());
app.use(express.json());
/**
* Service Initialization
*/
console.log(`Inicializando Servicios`);
app.use('/api/category', categoryRouter);
/**
* Server Activation
*/
const server = app.listen(PORT, () => {
console.log(`----------------------------------------------------------------`);
console.log(`--- App V 0.1 NodeJS Server Listening on port ${PORT} ---`);
console.log(`----------------------------------------------------------------`);
tsconfig.json :
{
"compilerOptions": {
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"sourceMap": true, /* Generates corresponding '.map' file. */ /* Enable all strict type-checking options. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
}
}
I want just the debugger to stay listening to break points, so when I trigger a request using postman, it stops on my categoryRouter function and I can see what's going on right there.
Now it just do nothing when I run it.
As far as I know there are 2 types of request when configuring a launch.json :
launch: which will launch a new server on its own.
attach: which tells to vscode whenver you press the start debug button, to attach the debbuger to an existing running process.
The first option is mostly used for when you want to debbug a script in the sense of, it can run on its own and it does not expect external input.
Second one can be used if you have your server already running on whatever port you have specified.
Try the following:
package.json:
{
"scripts": {
"build": "webpack",
"start": "nodemon --inspect=0.0.0.0:9229 lib/index.js",
...
}
}
Note lib/index.js is my compiled file, as I'm using ts in my project.
--inspect=...:9229 tells the running server to listen for a client connection (debugger) on the specified port.
if your server is running inside docker leave the host address to: 0.0.0.0 but if you're not using it, set it to: 127.0.0.1
Then you need to configure your .vscode/launch.json so that it can connect to the server.
this is the config I'm using:
{
"version": "0.2.0",
"configurations": [
{
"name": "Docker: Attach to Node",
"type": "node",
"request": "attach",
"restart": true,
"port": 9229,
"address": "localhost",
"localRoot": "${workspaceFolder}",
"remoteRoot": "/application",
"protocol": "inspector"
}
]
}
Note /application is the WORKDIR I have defined in my Dockerfile
if you're not using docker, you probably don't need this property.
With this set up, I can have docker running my server, and at any point I need to debug an endpoint in my server, I can simply run the debugger from vscode, and add a breakpoint in my source code, then from postman when I trigger a request, vscode will pause the execution at the breaking point.
Good luck, hope this helps. :)
I set my TypeORM config entities path like:
"entities": ["src/entities/**/*.ts"]
This works good when I use ts-node. ts-node src/main.ts
After compile typescripts using tsc, I got a dist folder with the compiled application:
However, typeORM still tries to get entities from the src folder instead of dist. throwing a lot of unexpectec syntax errors for parsing a TS file instead of a JS. So I change the fallowing string to the entities condiguration:
"entities": ["dist/entities/**/*.js"]
It works with node node dist/main.js but it does not works with ts-node src/main.ts
How can I configure ormconfig.json to be able to work with both (node at dist folder and ts-node at src folder)?
I'd suggest using an ormconfig.js instead of the JSON version and use an environment variable or similar to switch between the two configs. eg; something like the following stripped down example.
const srcConfig = {
"entities": [
"src/entities/**/*.ts"
],
}
const distConfig = {
"entities": [
"dist/entities/**/*.js"
],
}
module.exports = process.env.TS_NODE ? srcConfig : distConfig;
Note you'll need to set the TS_NODE env var somewhere; I did notice there's a PR not yet merged that will do it.
In addition to the existing answer:
I didn't like the idea to much to always work on the dist folder. Why? Because when I run commands from the command line I don't want to check whether dist is up-to-date, meaning was recently compiled.
So, I like my my typeorm commands like typeorm schema:sync work on the src! You can do that by running them via ts-node.
So, instead of
typeorm schema:sync
use
// Linux
ts-node ./node_modules/.bin/typeorm schema:sync
// Windows
ts-node ./node_modules/typeorm/cli.js schema:sync
Background
typeorm cli uses node, which relies on the files being compiled to javascript. So, that would only work on the /dist folder, which is the compiled version. However, that requires a watcher or similar running to capture changes of your ORM files. The described way here compiles typescript on-the-fly making a compilation not required. Source: https://github.com/typeorm/typeorm/blob/master/docs/faq.md#how-to-use-typeorm-with-ts-node
Based upon lock answer:
My full ormconfig.js
//npm install --save "detect-ts-node"
const detectTSNode = require('detect-ts-node');
const commonConfig = {
"type": "mssql",
"host": "127.0.0.1",
"port": 1433,
"username": "sa",
"password": "$$$$$$",
"database": "$$$$$$",
"synchronize": true,
"logging": false,
"options": {
"encrypt": false,
"enableArithAbort": false
}
};
const srcConfig = {
"entities": [
"src/entity/**/*.ts"
],
"migrations": [
"src/migration/**/*.ts"
],
"subscribers": [
"src/subscriber/**/*.ts"
],
"cli": {
"entitiesDir": "src/entity",
"migrationsDir": "src/migration",
"subscribersDir": "src/subscriber"
}
};
const distConfig = {
"entities": [
__dirname + "/dist/entity/**/*.js"
],
"migrations": [
__dirname + "/dist/migration/**/*.js"
],
"subscribers": [
__dirname + "/dist/subscriber/**/*.js"
],
"cli": {
"entitiesDir": __dirname + "/dist/entity",
"migrationsDir": __dirname + "/dist/migration",
"subscribersDir": __dirname + "/dist/subscriber"
}
};
const result = {};
let key;
// Append common configs to final object
for (key in commonConfig) {
if (commonConfig.hasOwnProperty(key)) {
result[key] = commonConfig[key];
}
}
if (detectTSNode) {
// if ts-node append src configuration
for (key in srcConfig) {
if (srcConfig.hasOwnProperty(key)) {
result[key] = srcConfig[key];
}
}
} else {
// else append dist configuration
for (key in distConfig) {
if (distConfig.hasOwnProperty(key)) {
result[key] = distConfig[key];
}
}
}
module.exports = result;
Usage in console.ts (my main file name)
import { createConnection } from "typeorm";
const conf = require('../ormconfig.js');
// Print the result for debuggin purposes
console.log(conf);
createConnection(conf).then(async connection => {
console.log("do your job here")
}).catch(error => {
console.log(error)
});
I've setup a project with several nodejs and angular apps inside a nrwl/nx workspace.
I'm trying to work with the environment files
inside the nodejs apps.
I've setup the import like this:
import {environment} from './environments/environment';
Then I ran ng serve my-node-app and it shows the environment for non production.
Now I tried to do ng serve my-node-app --prod to see how the app works with a production setup - but I get the error:
Configuration 'production' could not be found in project my-node-app.
Here's the project's angular.json config:
"ui-server": {
"root": "apps/ui/server",
"sourceRoot": "apps/ui/server/src",
"projectType": "application",
"prefix": "ui-server",
"schematics": {},
"architect": {
"build": {
"builder": "#nrwl/builders:node-build",
"options": {
"outputPath": "dist/apps/ui/server",
"main": "apps/ui/server/src/main.ts",
"tsConfig": "apps/ui/server/tsconfig.app.json",
"assets": ["apps/ui/server/src/assets"]
},
"configurations": {
"production": {
"optimization": true,
"extractLicenses": true,
"fileReplacements": [
{
"replace": "apps/ui/server/src/environments/environment.ts",
"with": "apps/ui/server/src/environments/environment.prod.ts"
}
]
}
}
},
"serve": {
"builder": "#nrwl/builders:node-execute",
"options": {
"buildTarget": "ui-server:build"
}
},
"lint": {
"builder": "#angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"apps/ui/server/tsconfig.app.json",
"apps/ui/server/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**"]
}
},
"test": {
"builder": "#nrwl/builders:jest",
"options": {
"jestConfig": "apps/ui/server/jest.config.js",
"tsConfig": "apps/ui/server/tsconfig.spec.json"
}
}
}
}
Am I missing something?
I've found this post when I was looking how to fetch the environmental variables defined in .env file.
process.env.ENVIRONMENTAL_VARIABLES in frontend part can be accessed when rendering on the server (e.g. Angular Universal), having .env in the root of Nrwl monorepo and webpack properties, such as:
const dotenv = require('dotenv-webpack');
module.exports = {
plugins: [
new dotenv(),
],
};
Don't forget to change your angular.json:
...
"architect": {
"build": {
"builder": "#angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.browser.config.js",
"replaceDuplicatePlugins": true
},
...
I've named the custom webpack as webpack.browser.config.js.
Now, let say you have a server/..., which you're using for some backend stuff, then you won't have them accessible there. You need to install dotenv package and in the server/main.ts, let say that's your server's root, require this package, that way:
require('dotenv').config();
Note: until Angular 8 we were able to set up also webpack-server related logic, in a file such as webpack.server.config.js. Therefore, it was doable to apply basically same code related to dotenv, which was in webpack.browser.config.js. However, it doesn't work anymore. Angular CLI Builders are being used to build & server SSR apps instead.
Deploying to Firebase/using Cloud Functions for Firebase (and possibly other Serverless/FaaS)?
Then in your functions folder you need to paste the .env file as well. I assume here that from functions you're deploying.
For debugging I'd advise:
console.log(require('dotenv').config({ debug: true }));
Might save you a lot of time.
Currently I'm working on a backend application using express + node.js and webpack as the bundler.
So far, I was able to run and test my code without any problem.
I would like now to use the Visual Studio Code debugger in order to debug my application. I tried to follow along this tutorial https://medium.com/#jsilvax/debugging-webpack-with-vs-code-b14694db4f8e
Now, when I try to launch my debugger, it just prints to the console Webpack is watching the files… without actually run my server
Here is my launch.json file:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Webpack",
"program": "${workspaceFolder}/node_modules/webpack/bin/webpack.js",
"args": [
"--config", "./webpack.config.js"
],
}
]
}
And here is my webpack.config.js file:
const webpack = require('webpack')
const path = require('path')
const nodeExternals = require('webpack-node-externals')
const StartServerPlugin = require('start-server-webpack-plugin')
module.exports = {
entry: ['webpack/hot/poll?1000', './src/index'],
watch: true,
devtool: 'sourcemap',
target: 'node',
node: {
__filename: true,
__dirname: true
},
externals: [nodeExternals({ whitelist: ['webpack/hot/poll?1000'] })],
module: {
rules: [
{
test: /\.js?$/,
use: [
{
loader: 'babel-loader',
options: {
babelrc: false,
presets: [['env', { modules: false }], 'stage-0'],
plugins: ['transform-regenerator', 'transform-runtime']
}
}
],
exclude: /node_modules/
},
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
use: {
loader: 'raw-loader'
}
}
]
},
plugins: [
new StartServerPlugin('server.js'),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
'process.env': { BUILD_TARGET: JSON.stringify('server') }
}),
new webpack.SourceMapDevToolPlugin({
filename: '[name].js.map'
}),
new webpack.BannerPlugin({ banner: 'require("source-map-support").install();', raw: true, entryOnly: false })
],
output: { path: path.join(__dirname, 'dist'), filename: 'server.js' }
};
Also, this is my project structure:
To run this application without using the debugger, I have a start script which looks like this:
"start": "webpack --colors --progress"
As I was saying, when I launch the debugger, it simply hangs and doesn't do anything. The only message I get inside the debugger console is Webpack is watching the files…
I'm think, that your configuration is not correct. In "program", choose file from your application, not from webpack, for example, "server.js" or as below, "index.js".
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/index.js"
}
There can be also other problem - do you have any breakpoints added in VSCode? If not, debugger just doesn't work.
I am very new to webpack, I found that in production build we can able to reduce the size of overall code.
Currently webpack builds around 8MB files and main.js around 5MB.
How to reduce the size of code in production build?
I found a sample webpack configurtion file from internet and I configured for my application and I run npm run build and its started building and it generated some files in ./dist/ directory.
Still these files are heavy(same as development version)
How to use these files? Currently I am using webpack-dev-server to
run the application.
package.json file
{
"name": "MyAPP",
"version": "0.1.0",
"description": "",
"main": "src/server/server.js",
"repository": {
"type": "git",
"url": ""
},
"keywords": [
],
"author": "Iam",
"license": "MIT",
"homepage": "http://example.com",
"scripts": {
"test": "",
"start": "babel-node src/server/bin/server",
"build": "rimraf dist && NODE_ENV=production webpack --config ./webpack.production.config.js --progress --profile --colors"
},
"dependencies": {
"scripts" : "", ...
},
"devDependencies": {
"scripts" : "", ...
}
}
webpack.config.js
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var public_dir = "src/frontend";
var ModernizrWebpackPlugin = require('modernizr-webpack-plugin');
module.exports = {
devtool: 'eval-source-map',
entry: [
'webpack-hot-middleware/client?reload=true',
path.join(__dirname, public_dir , 'main.js')
],
output: {
path: path.join(__dirname, '/dist/'),
filename: '[name].js',
publicPath: '/'
},
plugins: [
plugins
],
module: {
loaders: [loaders]
}
};
webpack.production.config.js
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var public_dir = "src/frontend";
var ModernizrWebpackPlugin = require('modernizr-webpack-plugin');
console.log(path.join(__dirname, 'src/frontend' , 'index.html'));
module.exports = {
devtool: 'eval-source-map',
entry: [
'webpack-hot-middleware/client?reload=true',
path.join(__dirname, 'src/frontend' , 'main.js')
],
output: {
path: path.join(__dirname, '/dist/'),
filename: '[name].js',
publicPath: '/'
},
plugins: [plugins],
resolve: {
root: [path.resolve('./src/frontend/utils'), path.resolve('./src/frontend')],
extensions: ['', '.js', '.css']
},
module: {
loaders: [loaders]
}
};
You can add the plugins as suggested by #Vikramaditya.
Then to generate the production build. You have to run the the command
NODE_ENV=production webpack --config ./webpack.production.config.js
If using babel, you will also need to prefix BABEL_ENV=node to the above command.
After observing number of viewers to this question I decided to conclude an answer from Vikramaditya and Sandeep.
To build the production code the first thing you have to create is production configuration with optimization packages like,
new webpack.optimize.CommonsChunkPlugin('common.js'),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.AggressiveMergingPlugin()
Then in the package.json file you can configure the build procedure with this production configuration
"scripts": {
"build": "NODE_ENV=production webpack --config ./webpack.production.config.js"
},
now you have to run the following command to initiate the build
npm run build
As per my production build configuration webpack will build the source to ./dist directory.
Now your UI code will be available in ./dist/ directory. Configure your server to serve these files as static assets. Done!
Use these plugins to optimize your production build:
new webpack.optimize.CommonsChunkPlugin('common'),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.AggressiveMergingPlugin()
I recently came to know about compression-webpack-plugin
which gzips your output bundle to reduce its size.
Add this as well in the above listed plugins list to further optimize your production code.
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8
})
Server side dynamic gzip compression is not recommended for serving static client-side files because of heavy CPU usage.
Just learning this myself. I will answer the second question:
How to use these files? Currently I am using webpack-dev-server to run the application.
Instead of using webpack-dev-server, you can just run an "express". use npm install "express" and create a server.js in the project's root dir, something like this:
var path = require("path");
var express = require("express");
var DIST_DIR = path.join(__dirname, "build");
var PORT = 3000;
var app = express();
//Serving the files on the dist folder
app.use(express.static(DIST_DIR));
//Send index.html when the user access the web
app.get("*", function (req, res) {
res.sendFile(path.join(DIST_DIR, "index.html"));
});
app.listen(PORT);
Then, in the package.json, add a script:
"start": "node server.js"
Finally, run the app: npm run start to start the server
A detailed example can be seen at:
https://alejandronapoles.com/2016/03/12/the-simplest-webpack-and-express-setup/
(the example code is not compatible with the latest packages, but it will work with small tweaks)
You can use argv npm module (install it by running npm install argv --save) for getting params in your webpack.config.js file and as for production you use -p flag "build": "webpack -p", you can add condition in webpack.config.js file like below
plugins: [
new webpack.DefinePlugin({
'process.env':{
'NODE_ENV': argv.p ? JSON.stringify('production') : JSON.stringify('development')
}
})
]
And thats it.
This will help you.
plugins: [
new webpack.DefinePlugin({
'process.env': {
// This has effect on the react lib size
'NODE_ENV': JSON.stringify('production'),
}
}),
new ExtractTextPlugin("bundle.css", {allChunks: false}),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
mangle: true,
compress: {
warnings: false, // Suppress uglification warnings
pure_getters: true,
unsafe: true,
unsafe_comps: true,
screw_ie8: true
},
output: {
comments: false,
},
exclude: [/\.min\.js$/gi] // skip pre-minified libs
}),
new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]), //https://stackoverflow.com/questions/25384360/how-to-prevent-moment-js-from-loading-locales-with-webpack
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0
})
],
In addition to Gilson PJ answer:
new webpack.optimize.CommonsChunkPlugin('common.js'),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.AggressiveMergingPlugin()
with
"scripts": {
"build": "NODE_ENV=production webpack -p --config ./webpack.production.config.js"
},
cause that the it tries to uglify your code twice. See https://webpack.github.io/docs/cli.html#production-shortcut-p for more information.
You can fix this by removing the UglifyJsPlugin from plugins-array or add the OccurrenceOrderPlugin and remove the "-p"-flag. so one possible solution would be
new webpack.optimize.CommonsChunkPlugin('common.js'),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.AggressiveMergingPlugin()
and
"scripts": {
"build": "NODE_ENV=production webpack --config ./webpack.production.config.js"
},
If you have a lot of duplicate code in your webpack.dev.config and your webpack.prod.config, you could use a boolean isProd to activate certain features only in certain situations and only have a single webpack.config.js file.
const isProd = (process.env.NODE_ENV === 'production');
if (isProd) {
plugins.push(new AotPlugin({
"mainPath": "main.ts",
"hostReplacementPaths": {
"environments/index.ts": "environments/index.prod.ts"
},
"exclude": [],
"tsConfigPath": "src/tsconfig.app.json"
}));
plugins.push(new UglifyJsPlugin({
"mangle": {
"screw_ie8": true
},
"compress": {
"screw_ie8": true,
"warnings": false
},
"sourceMap": false
}));
}
By the way:
The DedupePlugin plugin was removed from Webpack. You should remove it from your configuration.
UPDATE:
In addition to my previous answer:
If you want to hide your code for release, try enclosejs.com. It allows you to:
make a release version of your application without sources
create a self-extracting archive or installer
Make a closed source GUI application
Put your assets inside the executable
You can install it with npm install -g enclose
Latest answer including Webpack 5
For Webpack (version not remember)
NODE_ENV=production webpack --config ./webpack.production.config.js
For Webpack <4
plugins: [
new webpack.DefinePlugin({
'process.env':{
'NODE_ENV': JSON.stringify('production')
//for development -> JSON.stringify('development')
}
})
]
For webpack >=4 (Including webpack 5) - Specify mode
module.exports = {
mode: 'production', //for development -> development
devtool: 'inline-source-map',
...
};
Quote from Webpack's official website
Since webpack v4, specifying mode automatically configures
DefinePlugin for you