Open LorenDorez opened 3 years ago
Having this same issue. Would be awesome to hear someone got this working with an example.
I managed to solve this issue but last thing I need to do is remove/update the initialize JS that gets call to have it wrapped in the loadableready().
If you can bare with me a few days until I can fix that last part fix I'll post a walk through of what I have done to get this all up and working
That would be appreciated. Thanks
OK so here are the steps I took, im going to try and get some of this integrated into a PR for this project as well.
@edavis1993 I hope this helps. Feel free to Message me directly.
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const LoadableWebpackPlugin = require('@loadable/webpack-plugin')
const webpack = require("webpack")
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin")
const commonConfig = {
node: {
global: true,
//process: true,
__dirname: true,
//Buffer: true,
//setImmediate: true
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'babel-loader',
exclude: [/node_modules/, /\.stories\.tsx?$/]
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
}
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
}
}
const serverConfig = {
...commonConfig,
entry: ["@babel/polyfill", './Scripts/server.tsx'],
devtool: "source-map",
output: {
filename: 'server.js',
globalObject: 'this',
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
},
plugins: [new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
}),
new NodePolyfillPlugin()
],
resolve: {
...commonConfig.resolve,
fallback: {
//fs: require.resolve("browserify-fs"),
// path: require.resolve("path-browserify"),
// stream: require.resolve("stream-browserify"),
// buffer: require.resolve("buffer/"),
fs: false,
//path: false,
}
}
}
const clientConfig = {
...commonConfig,
target: "web",
entry: './Scripts/client.tsx',
output: {
filename: 'client-[name].[contenthash:8].js',
globalObject: 'this',
path: path.resolve(__dirname, 'wwwroot/dist'),
publicPath: '/dist/'
},
optimization: {
runtimeChunk: {
name: 'runtime', // necessary when using multiple entrypoints on the same page
},
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'vendor',
chunks: 'all',
},
},
},
},
plugins: [
new MiniCssExtractPlugin(),
new LoadableWebpackPlugin({
filename: '../../dist/loadable-stats.json',
}),
]
}
clientConfig.module.rules.push();
module.exports = [serverConfig, clientConfig];
public class LoadableFunction : RenderFunctionsBase
{
private readonly string nonce;
/// <summary>
/// HTML style tag containing the rendered scripts.
/// </summary>
public string Scripts { get; private set; }
/// <summary>
/// HTML style tag containing the rendered links.
/// </summary>
public string Links { get; private set; }
/// <summary>
/// HTML style tag containing the rendered styles.
/// </summary>
public string Styles { get; private set; }
private string Component { get; set; }
public LoadableFunction(string nonce = "")
{
this.nonce = nonce;
}
/// <summary>
/// Implementation of PreRender.
/// </summary>
/// <param name="executeJs"></param>
public override void PreRender(Func<string, string> executeJs)
{
string json = File.ReadAllText( @"dist/loadable-stats.json");
executeJs(@"var extractor = new Loadable.ChunkExtractor({ stats: "+ json +@"});");
}
/// <summary>
/// Implementation of WrapComponent.
/// </summary>
/// <param name="componentToRender"></param>
/// <returns></returns>
public override string WrapComponent(string componentToRender)
{
this.Component = componentToRender;
return this.Component;
}
/// <summary>
/// Implementation of PostRender.
/// </summary>
/// <param name="executeJs"></param>
public override void PostRender(Func<string, string> executeJs)
{
executeJs($"extractor.collectChunks({this.Component})");
this.Scripts = !string.IsNullOrEmpty(this.nonce) ? $"{executeJs("extractor.getScriptTags({ nonce: '" + this.nonce + "' })")}" : $"{executeJs("extractor.getScriptTags()")}";
this.Styles = !string.IsNullOrEmpty(this.nonce) ? $"{executeJs("extractor.getStyleTags({ nonce: '" + this.nonce + "' })")}" : $"{executeJs("extractor.getStyleTags()")}";
this.Links = !string.IsNullOrEmpty(this.nonce) ? $"{executeJs("extractor.getLinkTags({ nonce: '" + this.nonce + "' })")}" : $"{executeJs("extractor.getLinkTags()")}";
}
}
Ive read a few others who claim they got Loadable-Components to work. I can get this to work with client side just fine.
However, on SSR the component never actually renders under the client loads and calls the hydrate. I keep getting a 'document' is not defined error that ive atleast tracked down to the ChunkExtractor.
Has anyone else had success with this setup using ReactJS.net?