Webpack 5 Module federation : Unable to Import the Remote app - javascript

I have a vanilla JS app and an Angular app. I am trying to link both these apps using module federation, both on my local environment. The following is webpack config file for vanilla js app which acts as remote
module.exports = {
entry: ['./src/index.js'],
output: {
publicPath: config.get('publicPath')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: ['babel-loader'],
}
]
},
plugins: [
new HTMLWebpackPlugin({
template: path.resolve(__dirname, 'demo/index.html')
}),
new ModuleFederationPlugin({
name: 'remote',
exposes: {
'./createWidget': './src/index.js'
}
}),
],
devServer: {
host: "localhost.remote.org",
port: 8080
}
};
I ran the webpack dev server, so hitting http://localhost.remote.org:8080/remote.js will give me the file. So this is the webpack of my Angular app which is consuming the remote app:
module.exports = {
devtool: 'source-map',
context: __dirname,
entry: {
polyfills: './src/polyfills.ts',
main: './src/main.ts'
},
...
...
plugins : [
new ModuleFederationPlugin({
name: "HostApp",
remotes: {
remote: "remote#http://localhost.finra.org:8080/remote.js",
}
}),
]
}
Note I am trying to import the dependency in my component.ts file as follows:
import * as Widget from 'remote/createWidget'
When I run ng serve, I get the "module not found" error. I'm not sure what exactly is going wrong. How can I fix this?
Error: src/app/component1/component1.component.ts:30:28 - error TS2307: Cannot find module 'remote/createWidget' or its corresponding type declarations.
30 import * as Widget from 'remote/createWidget'

Related

Webpack errors with ssh2 package issue when upgrading from 0.8.9

I've recently picked up an Electron legacy project and I'm having issues with the ssh2 package https://www.npmjs.com/package/ssh2. From what I can see the project is quite outdated but for now I'm just trying to do the minimum to clear some security vulnerabilities discovered.
The one package I'm having issues with is ssh2. This project is using webpack albeit an old version but it's working just fine up to the point of upgrading ssh2.
During running my app in my dev env I'm getting webpack parsing errors, when I check out the syntax error it's referring to its pointing at an empty catch block. An example would be:
ERROR in ./~/ssh2/lib/server.js
Module parse failed: C:\Users\<my local path>\node_modules\ssh2\lib\server.js Unexpected token (484:16)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token (484:16)
at Parser.pp$4.raise (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:2221:15)
at Parser.pp.unexpected (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:603:10)
at Parser.pp.expect (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:597:28)
at Parser.pp$1.parseTryStatement (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:902:12)
at Parser.pp$1.parseStatement (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:702:31)
at Parser.pp$1.parseBlock (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:981:25)
at Parser.pp$3.parseFunctionBody (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:2105:24)
at Parser.pp$3.parseArrowExpression (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:2087:10)
at Parser.pp$3.parseParenArrowList (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:1902:17)
at Parser.pp$3.parseParenAndDistinguishExpression (C:\Users\<my local path>\node_modules\webpack\node_modules\acorn\dist\acorn.js:1870:21)
# ./~/ssh2/lib/index.js 33:10-32
And that is referring to this code:
onError: (err) => {
if (!proto._destruct)
socket.removeAllListeners('data');
this.emit('error', err);
try {
socket.end();
} catch {} << // Error is throw here
},
This is my webpack base config:
import path from 'path';
import WebpackNotifierPlugin from 'webpack-notifier';
export default {
module: {
loaders: [{
test: /\.jsx?$/,
loaders: ['babel-loader'],
exclude: /node_modules/
}, {
test: /\.json$/,
loader: 'json-loader'
}, {
test: /\.cjs?$/,
loaders: ['babel-loader']
}
]
},
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
libraryTarget: 'commonjs2'
},
resolve: {
extensions: ['', '.js', '.jsx', '.json', '.cjs'],
packageMains: ['webpack', 'browser', 'web', 'browserify', ['jam', 'main'], 'main']
},
plugins: [
new WebpackNotifierPlugin({excludeWarnings: true}),
],
externals: [
]
};
This is my webpack config for dev env:
/* eslint max-len: 0 */
import webpack from 'webpack';
import baseConfig from './webpack.config.base';
const config = {
...baseConfig,
debug: true,
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client?path=http://localhost:3000/__webpack_hmr',
'babel-polyfill',
'./app/index'
],
output: {
...baseConfig.output,
publicPath: 'http://localhost:3000/dist/'
},
module: {
...baseConfig.module,
loaders: [
...baseConfig.module.loaders,
{
test: /\.global\.css$/,
loaders: [
'style-loader',
'css-loader?sourceMap'
]
},
{
test: /^((?!\.global).)*\.css$/,
loaders: [
'style-loader',
'css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
]
}
]
},
plugins: [
...baseConfig.plugins,
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
],
target: 'electron-renderer'
};
export default config;
Please for give me if this issue is obvious. I've done some webpack work a long time ago and may be forgetting something fundamental. The issue only happens when I upgrade to any version of ssh2 client greater than 0.8.9.
Any help or pointers at all would be great and much appreciated.

Webpack Dev Server for React inside a legacy project

I recently added a React app into a legacy project.
The old code is based on a classic Nodejs + Express + Vanilla JS stack, and we wrote a whole new section of the project using React.
Everything works fine, since i configured webpack and Node routes to serve the output bundle on a specific path.
However, this way I do not have the live reload functionality, that's very useful. The bundling occurs correctly when a code change is detected, but to see that in the site, I need to refresh the page. That makes sense because I'm using our Node server to expose the whole frontend, React app included.
So, I was trying to add webpack-dev-server to the project in order to serve just the React part, exploiting its proxy option to communicate with my Express APIs.
That works in theory but I could not find the right configuration for the devServer, even to get my app runnig.
The code structure is something like:
- webpack.config.js
- server.js // Node + Express server
- app
- index.html // legacy app entry point
- js // legacy vanilla JS app
- react-app // new React section codebase
- dist
- src
- index.template.html // React app template
- index.js // React entry point
- Components // classic React components folder
Here's my webpack.config·js:
module.exports = env => {
const isProduction = Boolean(env.production);
return {
entry: path.resolve(__dirname, 'app/react-app/src/index.js'),
plugins: [
// new ReactRefreshWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'My App',
inject: 'body',
minify: isProduction,
template: path.resolve(__dirname, 'app/react-app/src/index.template.html')
}),
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/
})
],
output: {
path: path.resolve(__dirname, "app/react-app/dist"),
publicPath: '/react-app/dist/',
filename: "[name].[contenthash].js",
clean: true
},
devtool: isProduction ? false : 'inline-source-map',
devServer: {
port: 9000,
historyApiFallback: true
},
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
plugins: ['react-refresh/babel'],
}
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf|svg|png)$/i,
type: 'asset/resource',
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
]
},
optimization: {
moduleIds: 'deterministic',
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
}
};
Packages version:
"webpack": "^5.28.0",
"webpack-cli": "^4.6.0",
"webpack-dev-server": "^4.9.0"
I tried serveral options for the devServer object, but I couldn't find the right one. The best result I've got is to go from a Cannot GET / to a bunch of 404 for the js bundles :(
NOTE: This works perfectly when i just run webpack bundling and, at the same time, my Express server, with a route set like this:
app.get('/react-app', (req, res) => {
res.sendFile(process.cwd() + '/app/react-app/dist/index.html');
});
Any ideas?
Thank you so much.
Francesco

webpack module function not found

I have a simple project with a few html files in root folder and a few javascript modules in scripts directory.
I want to start using webpack now because I want minification and to start using environments. Everything was working before I started using webpack.
I read documentation for Webpack 5 but could not find anything that solves my problem. So I came up with this webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
entry: {
lib: "./scripts/lib.js"
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
devServer: {
contentBase: "./dist",
inline: true, //Enable watch and live reload
host: "localhost",
port: 8080,
stats: "errors-only",
https: false
},
plugins: [
new HtmlWebpackPlugin({
filename: "index.html",
template: "index.html",
hash: true
})
],
module: {
rules: [
{
test: /\.html$/i,
loader: 'html-loader',
},
],
},
};
My index.html imports and uses module functions like this:
<script type="module">
import * as lib from "./scripts/lib.js";
window.lib = lib;
</script>
<body onload="lib.myFn()">
</body>
But after running this webpack (using webpack serve) I am getting "is not a function" or "module not found" errors.
How can I compile and run my existing project with webpack without making any changes in my directory structure and fix this error so I can start using functions in lib.js in my index.html? Thanks.

MQTT.js and Webpack - "WS is not a constructor"

I am trying to bundle one of our microservices which is using MQTT.js and I am struggling with really strange issue.
It is working fine without bundling, so ws is available in node_modules.
Stuff which I think matters:
error:
TypeError: WS is not a constructor
at WebSocketStream (dist/index.js:159329:16)
at createWebSocket (dist/index.js:147450:10)
at Object.buildBuilderBrowser (dist/index.js:147476:10)
at MqttClient.wrapper [as streamBuilder] (dist/index.js:147937:36)
at MqttClient._setupStream (dist/index.js:146471:22)
at new MqttClient (dist/index.js:146452:8)
at Function.connect (dist/index.js:147940:10)
webpack config:
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const { NODE_ENV = 'production' } = process.env;
module.exports = {
entry: { index: './src/index.ts' },
mode: NODE_ENV,
target: 'node',
watch: NODE_ENV === 'development',
externals: [nodeExternals()],
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
resolve: {
extensions: ['.ts', '.js'],
},
node: {
__dirname: false,
},
module: {
rules: [
{
test: /\.ts$/,
use: [{ loader: 'ts-loader', options: { transpileOnly: true } }],
},
{
test: /(\.md|\.map)$/,
loader: 'null-loader',
},
],
},
};
Function where it happens:
createMqttClient(): MqttClient {
return mqtt.connect(this.mqttOptions.url, { ...this.mqttOptions.options });
}
The url is like: ssl://url-to-our-mqtt
Can anybody help please?
I also ran into same issue.
The problem for me was that I used
plugins: [
new webpack.NormalModuleReplacementPlugin(/^mqtt$/, "mqtt/dist/mqtt.js"),
],
in webpack.config.js order to fix the shebang error that comes with mqtt.js since it is a CLI tool.
Then instead I have used
{
test: [
/node_modules[/\\]mqtt[/\\]mqtt.js/,
/node_modules[/\\]mqtt[/\\]bin[/\\]sub.js/,
/node_modules[/\\]mqtt[/\\]bin[/\\]pub.js/,
],
loader: 'shebang-loader'
},
And my problem was fixed. Do you also use mqtt/dist/mqtt.js instead of mqtt in your imports or if you do something similar to mine, the shebang-loader rule I have posted above might solve your problem.
I experienced the same with Amazon aws-iot-device-sdk-js and Microsoft azure-iot-device-mqtt which both include mqtt.
The initial issue is the build error:
ERROR in ./node_modules/mqtt/mqtt.js Module parse failed: Unexpected character '#' (1:0)
This error is caused by the package mqtt. Three files (mqtt.js, pub.js and sub.js) contain a shebang line
#!/usr/bin/env node
The solution using module replacement suggested some places
plugins: [
new webpack.NormalModuleReplacementPlugin(/^mqtt$/, "mqtt/dist/mqtt.js"),
],
unfortunately changes the build error with the run time error
TypeError: WS is not a constructor
As mentioned in other answers, webpack can be configured (https://webpack.js.org/concepts/loaders/) to use the shebang loader (https://www.npmjs.com/package/shebang-loader)
TL;DR
Install shebang-loader
npm install shebang-loader --save
In webpack.config.js use the loader
module.exports = {
...
module: {
rules: [
{
test:
[
/.*mqtt\.js$/,
/.*sub\.js$/,
/.*pub\.js$/
],
use: 'shebang-loader'
}
]
}
}

Setup webpack with server side rendering to load Sass files in asp.net core project

I'm using a Yeoman project template called "aspnetcore-spa", which is an ASP.net core 1 template working in conjunction with major SPA frameworks (Angular2 and React).
I created a project with Angular2.The biolerplate's code works fine and there is no problem. Once I add Sass loader to webpack.config.js and make a reference to the Sass file from any angular file.
In webpack.config.js :
var isDevBuild = process.argv.indexOf('--env.prod') < 0;
var path = require('path');
var webpack = require('webpack');
var nodeExternals = require('webpack-node-externals');
var merge = require('webpack-merge');
var allFilenamesExceptJavaScript = /\.(?!js(\?|$))([^.]+(\?|$))/;
// Configuration in common to both client-side and server-side bundles
var sharedConfig = {
resolve: { extensions: [ '', '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
loaders: [
{ test: /\.ts$/, include: /ClientApp/, loader: 'ts', query: { silent: true } },
{ test: /\.scss$/,include:/ClientApp/, loaders: ["style", "css", "sass"] },
{ test: /\.html$/,include: /ClientApp/, loader: 'raw' },
{ test: /\.css$/, loader: 'to-string!css' },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'url', query: { limit: 25000 } }
]
}
};
// Configuration for client-side bundle suitable for running in browsers
var clientBundleOutputDir = './wwwroot/dist';
var clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot-client.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin()
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
var serverBundleConfig = merge(sharedConfig, {
entry: { 'main-server': './ClientApp/boot-server.ts' },
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map',
externals: [nodeExternals({ whitelist: [allFilenamesExceptJavaScript] })] // Don't bundle .js files from node_modules
});
module.exports = [clientBundleConfig, serverBundleConfig];
In my component :
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-wine',
template: require('./wine.component.html'),
styles: require('./wine.component.scss')
})
export class WineComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
I have already installed npm packages pertinent to sass loader :
npm install node-sass sass-loader --save-dev
I have checked the main-server.js file in wwwroot/dist folder which is the result of webpack bundling, I saw that the .scss file is loaded and they styles are processed correctly. Once I run the app though, shows this exception which is coming from the server side rendering side:
An unhandled exception occurred while processing the request.
Exception: Call to Node module failed with error: ReferenceError: window is not defined at E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:573:31 at E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:568:48 at module.exports (E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:590:69) at Object. (E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:526:38) at webpack_require (E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:20:30) at E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:501:22 at Object.module.exports (E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:506:3) at webpack_require (E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:20:30) at Object. (E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:129:25) at webpack_require (E:\Dev\MyApp\MyAppCore\src\MyApp.Web\ClientApp\dist\main-server.js:20:30)
It's obviously because of the webpack's server-side rendering, as it's running the code on Node.js side (through ASP.net Core's Javascript Services) and there is a code that is coupled with the DOM window object which is not valid on node.
Any clues?
I managed to fix the problem, here's the web.config.js bit:
(Notice the loaders for .scss files)
module: {
loaders: [
{ test: /\.ts$/, include: /ClientApp/, loader: 'ts', query: { silent: true } },
{ test: /\.scss$/,include:/ClientApp/, loaders: ["to-string", "css", "sass"] },
{ test: /\.html$/,include: /ClientApp/, loader: 'raw' },
{ test: /\.css$/, loader: 'to-string!css' },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'url', query: { limit: 25000 } }
]
}
And in the Angular component I changed the styles to this :
(Passed an array of required css files rather than a single css file)
#Component({
selector: 'app-wine',
template: require('./wine.component.html'),
styles: [require('./wine.component.scss')]
})

Categories

Resources