Window is not defined (Server-side rendering with Asp.Net SPA Services) - asp.net

Thank you guys for reading my question. Really hoping for a solution to this, I've been trying to find a fix for days to no avail.
Here's the rundown: My goal is to render a React application on the server-side using .NET Core. I haven't even started with the react part yet, right now I'm simply trying to render an h1 tag with the ASP.NET Javascript Services Prerendering functionality.
On my first iteration, I wrote my boot-server.js file with es5 and it worked perfectly. However, I quickly realized I was going to need to compile the file through webpack in order for it to understand my React code.
As soon as I piped that file through webpack though, I got a "window is not defined" error which I haven't been able to fix. I understand that part of my application should not be aware of the window object since it lives in the server but setting the webpack config's target field to node does not seem to fix the issue. Below are all the files involved.
Here is my boot-server.js file:
import { createServerRenderer } from 'aspnet-prerendering';
module.exports = createServerRenderer((params) => {
return new Promise((resolve, reject) => {
var html = '<h1>Hello world!</h1>';
resolve({
html: html
});
});
});
Here is my cshtml view:
#addTagHelper "*, Microsoft.AspNetCore.SpaServices"
<app id="root" asp-prerender-module="wwwroot/client/boot-server.bundle">Loading...</app>
Here is my webpack.config.js file:
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
const path = require("path");
const clientConfig = {
entry: './FrontEnd/index.js',
output: {
path: path.resolve(__dirname, "wwwroot/client"),
filename: "client.min.js",
publicPath: "/client/"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["es2015", "react", "stage-0"],
plugins: ["transform-class-properties", "transform-decorators-legacy", "react-html-attrs"]
}
}
},
{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "sass-loader"
}]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader?name=[name]_[hash:8].[ext]'
]
}
]
},
mode: 'development',
devServer: {
contentBase: './wwwroot/client',
hot: true
}
};
const bootServerConfig = {
stats: { modules: false },
resolve: { extensions: ['.js'] },
output: {
filename: '[name].js',
publicPath: '/wwwroot/client/', // Webpack dev middleware, if enabled, handles requests for this URL prefix
libraryTarget: 'commonjs'
},
entry: {
'main-server': './FrontEnd/boot-server.js'
},
module: {
rules: [
{
test: /\.js$/,
include: /FrontEnd/,
use: [
{
loader: "babel-loader",
options: {
presets: ["es2015", "react", "stage-0"],
plugins: ["transform-class-properties", "transform-decorators-legacy", "react-html-attrs"]
}
}
]
},
{
test: /\.svg$/,
use: {
loader: 'url-loader',
options: { limit: 25000 } //?limit=100000'
}
}
]
},
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './wwwroot/client')
},
target: 'node'
}
module.exports = [clientConfig, bootServerConfig];
Here is a screenshot of the error page:

Related

How can I load CSS styles using Webpack in React app?

I am having an issue with my React app. I have added Webpack and it is compiling successfully but, at the moment of serving the content, the app shows no styles at all.
This is what I have so far in my webpack.config.js file:
const path = require('path');
const BUILD_DIR = path.resolve(__dirname + '/public/build');
const APP_DIR = path.resolve(__dirname + '/src');
// This is the main configuration object.
// Here, you write different options and tell Webpack what to do
module.exports = {
experiments: {
asyncWebAssembly: true,
topLevelAwait: true,
layers: true // optional, with some bundlers/frameworks it doesn't work without
},
resolve: {
extensions: ['', '.js', '.jsx', '.css']
},
// Path to your entry point. From this file Webpack will begin its work
entry: [APP_DIR + '/index.js', APP_DIR + '/index.css', APP_DIR + '/App.css'],
// Path and filename of your result bundle.
// Webpack will bundle all JavaScript into this file
output: {
path: BUILD_DIR,
filename: 'bundle.js'
},
// Default mode for Webpack is production.
// Depending on mode Webpack will apply different things
// on the final bundle. For now, we don't need production's JavaScript
// minifying and other things, so let's set mode to development
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true,
},
},
{ loader: 'sass-loader' },
{ loader: 'postcss-loader' }
],
},
]
}
};
Is there anything I am missing to get my css to work? I only have two files, located at /src: App.css and index.css. None of them seem to be loaded and I have no errors in the console.
rules: [
{
test: /\.js|jsx$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.(sass|scss|less|css)$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.(png|jpe?g|svg|gif)$/,
loader: 'file-loader'
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader',
]
},
{
test: /\.css$/,
use: [
{
loader: 'url-loader',
options: {
limit: false
}
}
]
}
]

Node modules don't apply css

I'm new to React development and I try to use webpack to set up my project. Unfortunately, I have a problem with my configuration: with it, components from node_modules don't apply styles no matter if I try to build the application or to start it with webpack-dev-server.
My webpack.config.js:
const path = require('path')
const HtmlPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.jsx',
output: {
filename: 'main.js',
path: path.join(__dirname, 'dist')
},
resolve: {
extensions: ['.js', '.jsx']
},
plugins: [
new HtmlPlugin({
template: './src/index.html'
})
],
module: {
rules: [
{
test: /\.jsx?/i,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/i,
use: 'css-loader'
},
{
test: /\.(png|jpe?g|ttf|svg)/i,
use: 'file-loader'
},
]
},
devServer: {
port: 9000,
contentBase: path.join(__dirname, 'dist')
}
}
.babelrc:
{
"presets": ["#babel/preset-react"]
}
UPD: I didn't mean the styles I wrote, but the styles of the components themselves. For example, Button component of the primereact renders like the default html button.

Configure fonts in webpack

I have a slight problem with webpack here; I'm somewhat unable to load fonts.
This is my webpack.config.js
const nodeExternals = require('webpack-node-externals');
const path = require('path');
const devMode = true;
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry:
[
'./src/main.js',
'./scss/main.scss'
],
output: {
filename: "main.min.js",
chunkFilename: '[name].bundle.min.js?bust=[chunkhash]',
path: path.resolve(__dirname, 'static_root'),
publicPath: "/assets/"
},
target: "node",
externals: [nodeExternals()],
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
}),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.scss$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].css',
outputPath: 'css/'
}
},
{
loader: 'extract-loader'
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
hmr: process.env.NODE_ENV == 'development',
}
},
],
},
{
test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: '[name].[ext]'
}
}
]
}
};
This builds my css although then my local fonts aren't included / aren't rendered.. This also copies my Font to /static_root (which is where the css gets built to).
so I end up with this directory structure:
public/static_root/css/main.css
public/static_root/BebasNeue-Regular.ttf
public/static_root/main.min.js
I thought about just adjusting the path to the font in my scss file unfortunately though this lets the build process fail, since my working dir and the output root aren't the same.
My scss/font-directory is structured like so:
/public/scss/fonts/_fonts.scss
/public/scss/fonts/BebasNeueRegular.ttf
/public/scss/main.scss
So how can I achieve the inclusion of the font or how is this usually done since I found lots of different approaches online, that sadly didn't work out for me.
Any help would be greatly appreciated.
Greetings,
derelektrischemoench
So I found out what was causing the problems. It had to do something with the loader for the fonts (I was using an older one). I tried the whole thing with the url-loader like so:
{
test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: '[name].[ext]'
}
}
... which got it going. It was just kinda confusing, since I found a bazillion of tutorials on the web on how to achieve this, of which the most part was deprecated.
Thanks for the responses.
hey #derelektrischemoench, I think the example in Webpack official website is pretty good, you could follow the webpack config and its file structure:
https://webpack.js.org/guides/asset-management/#loading-fonts

Combining tailwind css with sass using webpack

I'm struggling a bit getting Tailwind CSS to work with SASS and Webpack. It seems like the postcss configuration for tailwind doesn't really do anything in terms of processing #tailwind preflight, #tailwind components and #tailwind utilities
My set up is as follows:
layout.scss
#import "~tailwindcss/preflight.css";
#import "~tailwindcss/components.css";
.my-class {
#apply text-blue;
#apply border-red;
}
#import "~tailwindcss/utilities.css";
entry.js
import '../css/src/layout.scss';
postcss.config.js
const tailwindcss = require('tailwindcss');
const purgecss = require('#fullhuman/postcss-purgecss');
const cssnano = require('cssnano');
const autoprefixer = require('autoprefixer');
module.exports = {
plugins: [
tailwindcss('./tailwind.js'),
cssnano({
preset: 'default',
}),
purgecss({
content: ['./views/**/*.cshtml']
}),
autoprefixer
]
}
webpack.config.js
// NPM plugins
const autoprefixer = require('autoprefixer');
const WebpackNotifierPlugin = require('webpack-notifier');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
entry: {
main: './scripts/entry.js'
},
output: {
filename: '[name].bundle.js',
publicPath: './'
},
watch: false,
externals: {
jquery: 'jQuery'
},
mode: 'development',
plugins: [
// Notify when build succeeds
new WebpackNotifierPlugin({ alwaysNotify: true }),
// Extract any CSS from any javascript file to process it as LESS/SASS using a loader
new MiniCssExtractPlugin({
fileame: "[name].bundle.css"
}),
// Minify CSS assets
new OptimizeCSSAssetsPlugin({}),
// Use BrowserSync plugin for file changes. I.e. if a CSS/SASS/LESS file changes, the changes will be injected directly in the browser with no page load
new BrowserSyncPlugin({
proxy: 'mysite.local',
open: 'external',
host: 'mysite.local',
port: 3000,
files: ['./dist/main.css', './views', './tailwind.js']
},
{
// disable reload from the webpack plugin since browser-sync will handle CSS injections and JS reloads
reload: false
})
],
module: {
rules: [
{
// Transpile ES6 scripts for browser support
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff)$/,
use: [
{
loader: 'file-loader'
}
]
},
{
// Extract any SCSS content and minimize
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader' },
{
loader: 'postcss-loader',
options: {
plugins: () => [autoprefixer()]
}
},
{
loader: 'sass-loader',
options: {
plugins: () => [autoprefixer()]
}
}
]
},
{
// Extract any CSS content and minimize
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
{ loader: 'postcss-loader' }
]
}
]
}
};
When I run Webpack, everything runs just fine, but the content of /dist/main.css is:
#tailwind preflight;#tailwind components;#tailwind utilities;.my-class{#apply text-blue;#apply border-red}
I suspect it's related to the (order of) loaders, but I can't seem to figure out why it's not getting processed correctly.
Does anyone know what I'm doing wrong here? :-)
Thanks in advance.
Wow, so after fiddling around with the loaders even more, I made it work :-) For future reference:
I added options: { importLoaders: 1 } to the css-loader for SCSS files and removed: plugins: () => [autoprefixer()] from the postcss-loader in my webpack.config.js file.
Full, updated webpack.config.js file:
// NPM plugins
const autoprefixer = require('autoprefixer');
const WebpackNotifierPlugin = require('webpack-notifier');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
module.exports = {
entry: {
main: './scripts/entry.js'
},
output: {
filename: '[name].bundle.js',
publicPath: './'
},
watch: false,
externals: {
jquery: 'jQuery'
},
mode: 'development',
plugins: [
// Notify when build succeeds
new WebpackNotifierPlugin({ alwaysNotify: true }),
// Extract any CSS from any javascript file to process it as LESS/SASS using a loader
new MiniCssExtractPlugin({
fileame: "[name].bundle.css"
}),
// Minify CSS assets
new OptimizeCSSAssetsPlugin({}),
// Use BrowserSync plugin for file changes. I.e. if a CSS/SASS/LESS file changes, the changes will be injected directly in the browser with no page load
new BrowserSyncPlugin({
proxy: 'mysite.local',
open: 'external',
host: 'mysite.local',
port: 3000,
files: ['./dist/main.css', './views', './tailwind.js']
},
{
// disable reload from the webpack plugin since browser-sync will handle CSS injections and JS reloads
reload: false
})
],
module: {
rules: [
{
// Transpile ES6 scripts for browser support
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff)$/,
use: [
{
loader: 'file-loader'
}
]
},
{
// Extract any SCSS content and minimize
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader',
options: {
plugins: () => [autoprefixer()]
}
}
]
},
{
// Extract any CSS content and minimize
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { importLoaders: 1 } },
{ loader: 'postcss-loader' }
]
}
]
}
};
There is an extension called tailwindcss-transpiler which compiles your layout.tailwind.scss files into pure CSS files.It also optimizing features.I hope it will be useful.
For VS Code
https://marketplace.visualstudio.com/items?itemName=sudoaugustin.tailwindcss-transpiler
For Atom
https://atom.io/packages/tailwindcss-transpiler

Webpack: extract css to its own bundle

I'm using webpack on a project. I use style-loader so I can import "my.css".
The css gets bundled with the javascript and will be rendered in a <style> tag when component mount, ok.
However, I would like to keep that import syntax and make webpack build a css bundle for every entry point.
So webpack output should be [name].bundle.js AND [name].bundle.css.
Is this something I can achieve ?
var config = {
entry: {
'admin': APP_DIR + '/admin.entry.jsx',
'public': APP_DIR + '/public.entry.jsx'
},
output: {
path: BUILD_DIR,
filename: '[name].bundle.js'
},
resolve: {
extensions: ['.js', '.jsx', '.json']
},
plugins: [],
devtool: 'cheap-source-map',
module: {
loaders: [{
test: /(\/index)?\.jsx?/,
include: APP_DIR,
loader: 'babel-loader'
},
{
test: /\.scss$/,
loaders: [
'style-loader',
'css-loader',
'sass-loader',
{
loader: 'sass-resources-loader',
options: {
resources: ['./src/styles/constants.scss']
},
}
]
}
],
}
};
along with this babel.rc:
{
"presets" : ["es2015", "react"],
"plugins": ["transform-decorators-legacy", "babel-plugin-root-import"]
}
Yes, you need to use extract-text-webpack-plugin. You might want to do it only on your production config. Config looks like this:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
//resolve-url-loader may be chained before sass-loader if necessary
use: ['css-loader', 'sass-loader']
})
}
]
},
plugins: [
new ExtractTextPlugin('style.css')
//if you want to pass in options, you can do so:
//new ExtractTextPlugin({
// filename: 'style.css'
//})
]
}

Resources