laravel-mix uses style-loader which is incompatible with SSR, additionally, it only provides one webpack output, whereas SSR requires multiple (one server, one client) as a work around, I'm currently using the following setup. First the idea is to make a new webpack config for mix, instead of using the default provided, create a webpack.config.js in the root project directory, and update the package.json scripts to point to it (production, development, hot). then create two 'mix' files, with a server and a client side bundle. Here I'm using pug templates and tailwind, but of course those are optional.
// webpack.config.js
const path = require("path");
// only build SSR target in production (this assumes SSR is desired & enabled)
const targets = process.env.NODE_ENV === "production"
? ["server", "client"]
: ["client"];
module.exports = Promise.all(
targets.map(async target => {
// we have to reset mix on every iteration otherwise each config will get merged in
// i.e. each entry in each config will get appended instead of replaced
global.Config = require("laravel-mix/src/config")();
global.Mix = new (require("laravel-mix/src/Mix"))();
// setup mix manually so we can individually target multiple configuration files
// this is required since for SSR to generate a seperate stylesheet the server bundles
// needs to be compiled differently
require("laravel-mix/src/index");
const ComponentFactory = require("laravel-mix/src/components/ComponentFactory");
const WebpackConfig = require("laravel-mix/src/builder/WebpackConfig");
require("laravel-mix/src/components/JavaScript").toCompile = [];
new ComponentFactory().installAll();
// build config
require(`./webpack.${target}.mix.js`); // change this
Mix.dispatch("init", Mix);
const config = new WebpackConfig().build();
config.name = target;
// replace all 'style-loader' with 'vue-style-loader'
for (let rule of config.module.rules) {
if (rule.loaders && rule.loaders.includes("style-loader")) {
rule.loaders.splice(
rule.loaders.indexOf("style-loader"),
1,
"vue-style-loader"
);
}
if (rule.use && rule.use.some(l => l.loader === "style-loader")) {
rule.use.splice(
rule.use.findIndex(l => l.loader === "style-loader"),
1,
{ loader: "vue-style-loader" }
);
}
}
return config;
})
);
// webpack.server.mix.js
const mix = require("laravel-mix");
const VueRouterAutoloadPlugin = require("@phased/webpack-plugin");
mix.webpackConfig({
target: "node",
resolve: {
alias: { "@": path.resolve(__dirname, "resources", "js") }
},
module: {
rules: [
{ test: /\.pug$/, loader: "pug-plain-loader" }
]
},
plugins: [
new VueRouterAutoloadPlugin({
output: path.resolve(__dirname, "node_modules/@phased/phase/routes.js"),
codeSplit: false
})
]
});
mix.js("node_modules/@phased/phase/app-server.js", `public/js`);
// webpack.client.mix.js
const mix = require("laravel-mix");
const VueRouterAutoloadPlugin = require("@phased/webpack-plugin");
const tailwindcss = require("tailwindcss");
const purgecss = require("@fullhuman/postcss-purgecss")({
content: [
"./resources/**/*.js",
"./resources/views/*.php",
"./resources/**/*.vue"
],
defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [],
whitelistPatterns: [/-active$/, /-enter$/, /-leave-to$/]
});
mix.webpackConfig({
resolve: {
alias: { "@": path.resolve(__dirname, "resources", "js") }
},
module: {
rules: [{ test: /\.pug$/, loader: "pug-plain-loader" }]
},
plugins: [
new VueRouterAutoloadPlugin({
output: path.resolve(__dirname, "node_modules/@phased/phase/routes.js"),
codeSplit: false // breaks ssr at the moment it seems...
})
]
});
mix.js("node_modules/@phased/phase/app-client.js", `public/js`);
mix.options({
processCssUrls: false,
postCss: mix.inProduction()
? [tailwindcss("./tailwind.config.js"), purgecss]
: [tailwindcss("./tailwind.config.js")],
extractVueStyles: "public/css/app.css"
});
laravel-mix uses
style-loaderwhich is incompatible with SSR, additionally, it only provides one webpack output, whereas SSR requires multiple (one server, one client) as a work around, I'm currently using the following setup. First the idea is to make a new webpack config for mix, instead of using the default provided, create awebpack.config.jsin the root project directory, and update the package.json scripts to point to it (production, development, hot). then create two 'mix' files, with a server and a client side bundle. Here I'm using pug templates and tailwind, but of course those are optional.