Node Webpack eval() sourcemaps - javascript

I am struggling setting up a Node project with TypeScript.
My workflow is: I run a Node script using nodemon. The node script creates a webpack compiler instance and sets the filesystem to MemoryFS. The webpack config includes loaders for TypeScript and Babel.
After webpack has finished compiling, if there are errors, I throw then, if not I fetch the result with MemoryFS and eval() it to run the code.
All of that works fine. But I tried to add sourcemaps support. I added a banner plugin in webpack which adds 'source-map-support'. In webpack, I set the devtool to 'source-map'. In tsconfig.json, I have the sourcemaps option enabled. In the src/index.ts I just throw an error, and at runtime Node doesn't tell me where did the error occur. (the sourcemap)
But if I run webpack normally, and then I run it using node dist/bundle.js. It is working.
I think there is a problem because of me using eval() to run the compiled output.
src/index.ts:
console.log('Hello world');
throw new Error('not');
build.js:
const path = require('path');
const webpack = require('webpack');
const MemoryFS = require('memory-fs');
const fs = new MemoryFS();
const config = require('./webpack.config');
const compiler = webpack(config);
compiler.outputFileSystem = fs;
compiler.run((err, stats) => {
console.clear();
const jsonStats = stats.toJson();
if(jsonStats.errors.length > 0 || jsonStats.warnings.length > 0)
return console.log(jsonStats.warning, jsonStats.errors);
const result = fs.readFileSync(path.resolve(__dirname, 'dist', 'bundle.js')).toString();
eval(result);
});
webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const SRC_DIR = path.resolve(__dirname, 'src');
const DIST_DIR = path.resolve(__dirname, 'dist');
module.exports = {
entry: SRC_DIR + '/index.ts',
output: {
path: DIST_DIR,
filename: 'bundle.js'
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.ts$/,
use: [
{ loader: 'babel-loader' },
{ loader: 'ts-loader' },
{ loader: 'tslint-loader' }
]
}
]
},
resolve: {
extensions: ['.ts', '.js', '.json']
},
target: 'node',
plugins: [
new webpack.BannerPlugin({
raw: true,
entryOnly: false,
banner: 'require("source-map-support").install();'
}),
new webpack.NoEmitOnErrorsPlugin()
]
};
After running webpack normally and executing the code (webpack && node dist\bundle.js, as expected):
C:\Users\shachar\Desktop\graph\dist\webpack:\src\index.ts:3
throw new Error('not');
^
Error: not
at Object.<anonymous> (C:\Users\shachar\Desktop\graph\dist\webpack:\src\index.ts:3:7)
at __webpack_require__ (C:\Users\shachar\Desktop\graph\dist\webpack:\webpack\bootstrap a6ba0885ca7e8b14ee63:19:1)
at C:\Users\shachar\Desktop\graph\dist\webpack:\webpack\bootstrap a6ba0885ca7e8b14ee63:62:1
at Object.<anonymous> (C:\Users\shachar\Desktop\graph\dist\bundle.js:67:10)
at Module._compile (module.js:573:30)
at Object.Module._extensions..js (module.js:584:10)
at Module.load (module.js:507:32)
at tryModuleLoad (module.js:470:12)
at Function.Module._load (module.js:462:3)
at Function.Module.runMain (module.js:609:10)
Running it using build.js:
Hello world
Error: not
at Object.eval (eval at compiler.run (C:\Users\shachar\Desktop\graph\build.js:23:5), <anonymous>:75:7)
at __webpack_require__ (eval at compiler.run (C:\Users\shachar\Desktop\graph\build.js:23:5), <anonymous>:21:30)
at eval (eval at compiler.run (C:\Users\shachar\Desktop\graph\build.js:23:5), <anonymous>:64:18)
at eval (eval at compiler.run (C:\Users\shachar\Desktop\graph\build.js:23:5), <anonymous>:67:10)
at compiler.run (C:\Users\shachar\Desktop\graph\build.js:23:5)
at emitRecords.err (C:\Users\shachar\Desktop\graph\node_modules\webpack\lib\Compiler.js:269:13)
at Compiler.emitRecords (C:\Users\shachar\Desktop\graph\node_modules\webpack\lib\Compiler.js:375:38)
at emitAssets.err (C:\Users\shachar\Desktop\graph\node_modules\webpack\lib\Compiler.js:262:10)
at applyPluginsAsyncSeries1.err (C:\Users\shachar\Desktop\graph\node_modules\webpack\lib\Compiler.js:368:12)
at next (C:\Users\shachar\Desktop\graph\node_modules\tapable\lib\Tapable.js:218:11)
Thanks for any help!

When you use eval to run the code, Node will have no idea about the source map. Perhaps you can try to run a child node process instead of using eval to run the result, or is there any reason you're using eval? See https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback

Related

Getting 'ReferenceError: document is not defined' only when I run webpack --watch?

Why would document stop being defined only when I run webpack --watch? When I run my build or dev script, compiling works great. It's only when I try and watch. New to WP.
My end goal here is to polyfill my client-side JS and auto-reload the browser window that LiveServer opens (VSCode plugin). Right now, I'm just trying to automatically compile my code after making changes which will trigger LiveServer to reload. Is there a better approach to this?
index.js
const errors = document.querySelector('.errors');
webpack.config.js
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const NodemonPlugin = require('nodemon-webpack-plugin');
const config = {
watch: true,
entry: {
rater_stater: "./src/index.js",
},
output: {
filename: "index.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
MiniCssExtractPlugin.loader,
// Translates CSS into CommonJS
"css-loader",
// Compiles Sass to CSS
"sass-loader",
"postcss-loader",
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: "style.css",
chunkFilename: "style-[id].css",
}),
new NodemonPlugin({
env: {
NODE_ENV: 'development',
},
})
],
};
module.exports = (env, argv) => {
if (argv.mode === "development") {
config.devtool = "source-map";
}
if (argv.mode === "production") {
config.module.rules.push({
test: /\.js?$/,
use: [
{
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
],
exclude: /node_modules/,
});
}
return config;
};
package.json
"scripts": {
"build": "webpack --mode=production",
"dev": "webpack --mode=development",
"watch": "webpack --watch"
},
error
ReferenceError: document is not defined
at /Users/brad/Documents/vscode/rater-stater/dist/index.js:1:180375
at /Users/brad/Documents/vscode/rater-stater/dist/index.js:1:180732
at Object.<anonymous> (/Users/brad/Documents/vscode/rater-stater/dist/index.js:1:180735)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47
[nodemon] app crashed - waiting for file changes before starting...
Edit:
I'm also getting this error when it does compile with webpack --mode=development. It's like my variables are all set to null? I'm so confused. Why would this happen? I've tried changing it from var to let to const and still get the same error.
Edit 2:
Ran a couple more tests. It's like everything related to document is broken.. but I can console.log document. I just can't use querySelector, etc.
All of these issues stopped when I wrapped my code with
document.addEventListener("DOMContentLoaded", function() {
...code
}
🤦

How to transform import syntax from node_modules with Babel in a NextJS application? [duplicate]

This question already has answers here:
"Cannot use import statement outside a module" error when importing react-hook-mousetrap in Next.js
(2 answers)
Closed 12 months ago.
when transpiling es6 modules from my node_modules with Babel my build breaks with the following error:
SyntaxError: Cannot use import statement outside a module
at wrapSafe (internal/modules/cjs/loader.js:915:16)
at Module._compile (internal/modules/cjs/loader.js:963:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
at Module.load (internal/modules/cjs/loader.js:863:32)
at Function.Module._load (internal/modules/cjs/loader.js:708:14)
at Module.require (internal/modules/cjs/loader.js:887:19)
at require (internal/modules/cjs/helpers.js:74:18)
I use the following nextJS / webpack config:
const withLess = require('#zeit/next-less');
const withPreact = require('next-plugin-preact');
const path = require('path');
module.exports = withPreact(withLess( {
webpack: (config) => {
config.module.rules.push({
test: /\.js|jsx$/,
include: (modPath) => {
return modPath.indexOf('#my-org') !== -1 || modPath.indexOf('node_modules') === -1
},
use: {
loader: 'babel-loader',
options: {
presets: ['next/babel','#babel/preset-flow','#babel/preset-env']
},
},
});
return config;
},
}));
It seems the modules from my organisation are not transformed. Although I can confirm they are "included" by checking the include function.
How does one get babel to transform es6 modules from the node_modules folder?
I solved with this webpack plugin:
https://www.npmjs.com/package/next-transpile-modules
const withLess = require('#zeit/next-less');
const withPreact = require('next-plugin-preact');
const withTM = require('next-transpile-modules')(()=>{
// should return array with module paths
});
module.exports = withTM(withPreact(withLess( {
webpack: (config) => {
config.module.rules.push({
test: /\.js|jsx$/,
use: {
loader: 'babel-loader',
options: {
presets: ['next/babel','#babel/preset-flow','#babel/preset-env']
},
},
});
return config;
},
})));

Webpack config not accepting to config mode option

**getting error when trying to add mode option to the webpack config i need to configure {mode:'developement' } to enable hmp by looking at this answer github.com/webpack-contrib/webpack-hot-middleware/issues/… **
WebpackOptionsValidationError: Invalid configuration object. Webpack
has been initialised using a configuration object that does not match
the API schema.
- configuration has an unknown property 'mode'. These properties are valid:
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry, externals?, loader?, module?, name?,
node?, output?, performance?, plugins?, profile?, recordsInputPath?,
recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?,
target?, watch?, watchOptions? }
For typos: please correct them.
For loader options: webpack 2 no longer allows custom properties in configuration.
Loaders should be updated to allow passing options via loader options in module.rules.
Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:
plugins: [
new webpack.LoaderOptionsPlugin({
// test: /.xxx$/, // may apply this only for some modules
options: {
mode: ...
}
})
]
at webpack (C:\Users\asdf\WebstormProjects\node_modules\webpack\lib\webpack.js:19:9)
at Object. (
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
at startup (internal/bootstrap/node.js:282:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:743:3)
/* eslint-disable */
const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const commonConfig = require('./webpack.config.common');
module.exports = webpackMerge(
commonConfig,
{
devtool: 'cheap-module-eval-source-map',
entry: {
main: ['babel-polyfill', 'webpack-hot-middleware/client', './app/index.js'],
},
output: {
path: __dirname,
publicPath: '/',
filename: '[hash].bundle.js',
},
module: {
rules: [
{
test: /\.mspcss/,
use: [
'style-loader',
'css-loader?modules=true&importLoaders=1&localIdentName=[local]___[hash:base64:5]',
'resolve-url-loader',
'sass-loader?sourceMap'
]
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader?sourceMap']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development'),
BABEL_ENV: JSON.stringify('development'),
},
__DEV__: true,
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoErrorsPlugin(),
new HtmlWebpackPlugin({
title: 'some- Development',
template: path.resolve(__dirname, 'index.ejs'),
filename: path.resolve(__dirname, 'index.html'),
favicon: 'favicon.ico',
inject: 'body'
}),
]
}
)
/* eslint-enable */
What version of webpack are you using? You are probably on version 2 or 3 and the latest version of webpack-dev-server (3.2.1) targets webpack 4. I had the same issue and fixed it by installing webpack-dev-server version 2.11.5
npm uninstall webpack-dev-server
npm i -D webpack-dev-server#2.11.5

renderToString causes an Uncaught ReferenceError: require is not defined

I am currently facing this issue for 3 days and unable to resolve:
Uncaught ReferenceError: require is not defined
at Object.<anonymous> (external "stream":1)
at n (bootstrap:19)
at Object.<anonymous> (react-dom-server.node.production.min.js:10)
at n (bootstrap:19)
at Object.<anonymous> (server.node.js:4)
at n (bootstrap:19)
at Object.<anonymous> (server.js:3)
at n (bootstrap:19)
at Object.<anonymous> (renderer.js:2)
at n (bootstrap:19)
Basically, in my file renderer.js, I have this functionality:
import {renderToString} from 'react-dom/server';
export default (req) => {
let context = {};
const content = renderToString(
<Router location={req.path} context={context}>
<FullPage />
</Router>
);
};
This is the main line which is causing the error basically, this happens when I try to import the renderToString method from 'react-dom/server':
I have tried out different things like removing target: 'node' but none of the solutions worked. What possible might be causing this? I have been stuck on this for the last 3 days and not sure what it is.
My Webpack configuration is:
webpack.base.config.js
module.exports = {
devtool: 'source-map',
module: {
rules: [
{
test: /\.js?$/,
options: {
presets: [
'react', 'stage-2',
['env', { targets: { browsers: ['last 2 versions'] } }]
]
},
loader: 'babel-loader',
exclude: /node_modules/
}
]
}
};
webpack.server.js
const webpack = require('webpack');
const path = require('path');
const SERVER_DIR = path.resolve(__dirname, 'src/server');
const BUILD_DIR = path.resolve(__dirname, 'dist');
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base.config');
const config = {
target: 'node',
entry: SERVER_DIR + '/index.js',
mode: 'production',
output: {
path: BUILD_DIR,
filename: 'bundle.server.js'
}
};
module.exports = merge(baseConfig, config);

Can I load a file from a bundled javascript application?

I have a node application that when built is bundled all into one file. I want to split out of this bundle the app configuration parameters (it's just a simple object).
The ./build directory becomes populated with only three files: index.js, config.js and a map file.
When I cd into the directory and launch the app with node index.js, I get the following error:
TypeError: Cannot read property 'logPath' of undefined
at Module.<anonymous> (/home/*/repo/build/index.js:1:2367)
at t (/home/*/repo/build/index.js:1:172)
at /home/*/repo/build/index.js:1:964
at Object.<anonymous> (/home/*/repo/build/index.js:1:973)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Function.Module.runMain (module.js:693:10)
at startup (bootstrap_node.js:191:16)
at bootstrap_node.js:612:3
The top of the built config.js file looks like
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.config = {
logPath: 'logs',
....
};
The webpack configuration I am using looks as such
const path = require('path');
const nodeExternals = require('webpack-node-externals');
function excludeConfig(context, request, callback) {
/config/.test(request)
? callback(null, 'require("./config.js")', + request)
: callback();
}
module.exports = {
entry: {
index: path.resolve(__dirname, './src/server/index.js')
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'awesome-typescript-loader',
exclude: ['node_modules']
}, {
test: /\.js$/,
loader: 'source-map-loader',
enforce: 'pre'
}
]
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
modules: [path.resolve(__dirname, 'node_modules')]
},
devtool: 'source-map',
output: {
filename: 'index.js',
path: path.join(__dirname, '/build')
},
mode: 'production',
target: 'node',
externals: [
nodeExternals(),
excludeConfig
],
};
My config file is being built by gulp with the following strategy
const ts = require('gulp-typescript');
const tsProject = ts.createProject('tsconfig.json');
gulp.task('add-config', function () {
return gulp
.src('src/*config.ts')
.pipe(tsProject())
.pipe(gulp.dest('build'));
});
The tsconfig.json file looks as follows:
{
"compilerOptions": {
"outDir": "./build",
"allowJs": true,
"checkJs": false,
"module": "commonjs",
"target": "es5",
"moduleResolution": "node",
"lib": ["es2015", "dom"]
}
}
My hunch is that after the build the configuration file is not providing what the bundle is expecting.
The bundle does contain the following line:
function (e, r) { e.exports = require("./config.js") }
Any ideas on how I can make the bundle load the config.js file?
It seems that after much static analysis, and lack of a comprehensive understanding of the different ways to import modules, for some reason the bundle defines my config file to be a harmony import and attempts to retrieve a default from the file (which in my case I hadn't any).
There are two fixes available (both worked fine):
change the import style away from using defaults by using brackets around the import (I don't know why I prefer this)
import { config } from './../../config';
change the export style and adopt the default route
export default <Config>{
logPath: 'logs',
...
};
To be honest, I don't know why this worked before when this project had still not started the migration to TypeScript. I know that everything babel related was removed before I started so I can't get my head around it.
Webpack Internals
The module loader looks like this:
(function(module, exports) {
module.exports = require("./config.js");
})
It is then passed on to another module and loaded as follows:
/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./../../config */ "./../config");
/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_config__WEBPACK_IMPORTED_MODULE_1__);
const PATH = _config__WEBPACK_IMPORTED_MODULE_1___default.a.logPath.replace(/\/*$/, '');
Notice how _config__WEBPACK_IMPORTED_MODULE_1__ already has the contents of my configuration object. However, webpack sends it into a function n which encapsulates the import into a getter function on member a. This encapsulation resolves to using default if the module was marked as an esModule
__webpack_require__.n = function(module) {
var getter = module && module.__esModule ?
function getDefault() { return module['default']; } :
function getModuleExports() { return module; };
__webpack_require__.d(getter, 'a', getter);
return getter;
};

Categories