Skip to content

current webpack config doesn't allow style tags in .vue components #4

Description

@reed-jones

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"
});

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions