I made a webapp with angular. I want server side rendering with Angular Universal.
The best way to build such a server is by using webpack, this is the standard configuration which works for most of the cases:
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: { server: './server.ts' },
resolve: { extensions: ['.js', '.ts'] },
target: 'node',
externals: [/node_modules/],
mode: 'none',
// this makes sure we include node_modules and other 3rd party libraries
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [{ test: /\.ts$/, loader: 'ts-loader', exclude: /server-local/ }]
},
plugins: [
// Temporary Fix for issue: https://github.com/angular/angular/issues/11580
// for 'WARNING Critical dependency: the request of a dependency is an expression'
new webpack.ContextReplacementPlugin(
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'),
{}
)
]
};
But I got a problem: I use the node module pug-mailer in my server and it uses uglify-js as dependency and not dev dependencies. Webpack has no support in bundling uglify-js, so the only way I found to solve this problem was this:
const nodeExternals = require('webpack-node-externals');
module.exports = {
externals: [nodeExternals()],
... //the rest is unchanged
};
But it cannot be accepted: with this, all node_modules are not bundled and I have to keep the entire node_modules dir in my production server.
Is there a way to bundle all the node_modules in only one file except for uglify-js?
The result I want is this:
dist
----server.js //built with webpack, contains all node_modules except uglify-js
----other dists folder
node_modules
----uglify-js //Only this dependency in node_modules
Related
I have a legacy code for my express app that read all routes files in specific dir and require them in a loop. Notice this code cant be changed:
app.js
const normalizedRoutes = fs.readdirSync(__dirname + '/src/routes/')
.map(routeFile => `/src/routes/${routeFile}`);
normalizedRoutes.forEach((normalizedRouteDir: string) => {
require(normalizedRouteDir)(app);
})
Now, I want to combine a Server Side Rendered application with the code above, using some JSX in routes files.
My problem is because the routes files are loaded on run time webpack not recognize them when creating the bundle.js file.
Therefore there are not routes files in the /src/routes/${routeFile} and when I run the bundle.js file I get an error message of:
Error: ENOENT: no such file or directory, scandir '/Users/******/build/src/routes/'
(the stars are for hiding full path)
webpack configs:
webpack.base.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: { //remain
rules: [
{
test: /\.(ts|js)x?$/,
loader:'babel-loader',
exclude: /node_modules/,
options:{
presets:[
'#babel/react',
['#babel/env',{targets:{browsers:['last 2 versions']}}]
]
}
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
}
};
webpack.server.js
const path = require('path')
const {merge} = require('webpack-merge')
const baseConfig = require('./webpack.base.js');
const webpackNodeexternals = require('webpack-node-externals');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const config = {
mode: "development",
entry: {
main:"./app.ts",
},
resolve: {
extensions: [".js", ".jsx", ".json", ".ts"],
},
node: {
__dirname: true
},
output: {
libraryTarget: "commonjs",
path: path.join(__dirname, "build"),
filename: "bundle.js",
},
target: "node",
//Avoid put node modules of server when sending to browser
externals: [webpackNodeexternals()]
}
module.exports = merge(baseConfig,config)
scripts from package.json:
"dev:server": "nodemon --watch build --exec \"node build/bundle.js\" ",
"dev:build-server": "webpack --config webpack.server.js --watch",
When I copy the route files (js files) to the build directory it works of course but that means I don't run webpack on these files and therefore I can't include JSX\es6 features inside these files.
So my question is:
Is there any possible way to make these requires identify by webpack/babel to add them to bundle.js and avoid the need for seperate files (bundle.js and routes files)
If we cant do it, how can I run webpack on a folder seperatly from the bundle.js output and create a route folder in the correct path but after processed by babel?
Thanks!
Instead of using a Webpack you can try using a programmatic interface of babel, and transpile the files before requiring them.
Here is the link https://babeljs.io/docs/en/babel-core
• I recently implemented server side rendering using Angular Universal in my application.
• This required converting my node server file from .js to .ts.
• Typescript is compiled to javascript using webpack
• Everything works when I run the server using : ts-node server.ts
• After compiling to javascript using webpack, I get the following error for Firebase API's used in my server:
ERROR in ./node_modules/google-auto-auth/node_modules/mime/index.js
Module not found: Error: Can't resolve './types/standard' in '/Users/XX/Desktop/XX/XX/node_modules/google-auto-auth/node_modules/mime'
ERROR in ./node_modules/#google-cloud/storage/node_modules/mime/index.js
Module not found: Error: Can't resolve './types/standard' in '/Users/XX/Desktop/XX/OM-XX/node_modules/#google-cloud/storage/node_modules/mime'
etc. etc.
How can this be tackled?
My webpack config code:
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: {server: './server.ts'},
resolve: {extensions: ['.js', '.ts']},
target: 'node',
mode: 'none',
// this makes sure we include node_modules and other 3rd party libraries
externals: [/(node_modules|main\..*\.js)/],
output: {
path: __dirname,
filename: '[name].js'
},
module: {
rules: [
{test: /\.ts$/, loader: 'ts-loader'}
]
},
plugins: [
// Temporary Fix for issue: https://github.com/angular/angular/issues/11580
// for "WARNING Critical dependency: the request of a dependency is an expression"
new webpack.ContextReplacementPlugin(
/(.+)?angular(\\|\/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
/(.+)?express(\\|\/)(.+)?/,
path.join(__dirname, 'src'),
{}
)
]
}
Thank you!
Maybe this can be related to missing types?
Try to install missing typesfor all the packages that throw error
e.g: npm install --save #types/google-cloud__storage
I am developing a serverless application using the Serverless Framework. I need webpack to compile the .js files inside root folder as well as 'src' folder. The config file and 'src' folder are right inside root folder. This is the webpack.config.js file
var glob = require('glob');
var path = require('path');
var nodeExternals = require('webpack-node-externals');
// Required for Create React App Babel transform
process.env.NODE_ENV = 'production';
module.exports = {
// Use all js files in project root (except
// the webpack config) as an entry
entry: globEntries('!(webpack.config).js'),
target: 'node',
// Since 'aws-sdk' is not compatible with webpack,
// we exclude all node dependencies
externals: [nodeExternals()],
// Run babel on all .js files and skip those in node_modules
module: {
rules: [{
test: /\.js$/,
loader: 'babel-loader',
include: __dirname,
exclude: /node_modules/,
}]
},
// We are going to create multiple APIs in this guide, and we are
// going to create a js file to for each, we need this output block
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, '.webpack'),
filename: '[name].js'
},
};
function globEntries(globPath) {
var files = glob.sync(globPath);
var entries = {};
for (var i = 0; i < files.length; i++) {
var entry = files[i];
entries[path.basename(entry, path.extname(entry))] = './' + entry;
}
return entries;
}
Every time I make changes to my website, I fetch them from github. I run webpack in the terminal, which appears to work. Then I run my expressHost.js file to host my site. When i access that site I get the error in the title.
To fix this i delete the folder, git clone, npm install, webpack, node expressHost.js and it works like nothing was ever wrong. any ideas?
Simular issues do not seem to be happening on my dev machine, only my VPS.
my webpack config
module.exports = {
entry: [
'./src/index.js'
],
output: {
path: __dirname,
publicPath: '/',
filename: 'bundle.js'
},
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015', 'stage-1']
}
}]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devServer: {
historyApiFallback: true,
contentBase: './'
}
};
my expressHost
const express = require('express');
const app = express();
const path = require('path');
app.listen(7070, () => {
console.log('listening 7070...');
})
app.use(express.static(path.join(__dirname, 'public')));
my public folder has index.html, bundle.js, and styles folder. Everything was made using React and is hosted with nginx. I am new to deployment, I have only launched one other site (which works, NG1)
this is the error i get when running webpack... this does not happen on the local machine.
Hash: d437a155a1da4cdfeeeb
Version: webpack 1.14.0
Time: 77ms
Asset Size Chunks Chunk Names
bundle.js 1.51 kB 0 [emitted] main
[0] multi main 28 bytes {0} [built] [1 error]
+ 1 hidden modules
ERROR in The node API for `babel` has been moved to `babel-core`.
# multi main
https://github.com/babel/babel-loader/issues/259
https://www.codementor.io/tamizhvendan/tutorials/beginner-guide-setup-reactjs-environment-npm-babel-6-webpack-du107r9zr
So I was having the error listed above but the page was still working on my local machine. When I posted any changes I would get that error but it seemed to work, When users viewed the machine they would get the error in the title.
to install babel loader correctly I have to change the webpack config to module{ loaders {[ loader: 'babel-loader' this seemed to solve the issue of babel being moved into babel-core's folder
also (probably the real issue) npm needed to install, in terminal
npm i babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-1 -S
because the webpack config had module{ loaders {[ query: { presets: ['react', 'es2015', 'stage-1']
the website appears to be fetching and compiling websites like normal.
I am following a few tutorials, but mainly the one by Dan Abramov on setting up react hot loader but I am having some issues. I think I have a basic configuration working, however hot reloading of component does not seem to work, so obviously the hot loader set up is wrong :(
When I change a component, my browser console logs this:
The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.
- ./app/components/Home/index.jsx
To start off, here is my file structure:
.
|++[app]
|----[actions]
|----[modules]
|----[reducers]
|----[store]
|----index.html
|----index.js
|--[config]
|----server.js
|----webpack.config.js
|--[node_modules]
|--package.json
Here's my webpack config:
var webpack = require('webpack');
var path = require('path');
var autoprefixer = require('autoprefixer');
var isProd = process.env.NODE_ENV === 'production';
module.exports = {
devtool: isProd ? null : 'source-map',
entry: [
'webpack-hot-middleware/client',
path.resolve('app/index.js')
],
output: {
path: path.resolve('dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
resolve: {
root: path.resolve( 'app/'),
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
loaders: [
'babel'
],
include: path.resolve('.'),
exclude: /node_modules/
},
{
test: /\.(png|jpg)$/,
loader: 'file-loader?name=img/[name].[ext]'
},
{
test: /\.scss$/,
loader: 'style!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]!postcss!sass'
}
]
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin()
],
postcss: [
autoprefixer({ browsers: ['last 3 versions'] })
]
};
And my server.js
var webpack = require('webpack');
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var config = require('./webpack.config');
var path = require('path');
var app = new (require('express'))();
var port = 3000;
var compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }));
app.use(webpackHotMiddleware(compiler));
app.get('/*', function(req, res) {
res.sendFile(path.resolve('app/index.html'));
});
app.listen(port, function(error) {
if (error) {
console.error(error);
} else {
console.info('started on localhost://%s.', port);
}
});
The react-hot loader is missing within your module.loaders array. More into this.
Next we need to tell Webpack to use React Hot Loader for the components. If you configured Webpack for React, you may already use babel-loader (ex 6to5-loader) or jsx-loader for JS(X) files. Find that line in webpack.config.js and put react-hot before other loader(s).
So you need to add the react-hot loader before your babel loader, like so:
{
test: /\.jsx?$/,
loader: 'react-hot',
exclude: /node_modules/
}
And also you need to install the react-hot-loader module if you haven't already.
npm i -D react-hot-loader