Skip to content

Client-side rendered template adds additional Carriage Return characters to DOM #9207

Closed
@DominikSerafin

Description

@DominikSerafin

Version

vue: 2.5.21
vue-server-renderer: 2.5.21
vue-template-compiler: 2.5.21
vue-loader: 15.4.2
webpack: 4.27.1
@babel/core: 7.2.0
@babel/plugin-transform-runtime: 7.2.0
@babel/preset-env: 7.2.0

(I'm not sure, but I think this problem was non-existent when I was using vue-loader@13)

Reproduction link

(Needs build step)

Steps to reproduce

  1. Write source code with markup elements that have new lines in it
  2. Build it & run it (or hot-reload in development environment)
  3. (More info in the image below)

What is expected?

Line feeds, carriage returns and whitespaces should be removed from the compiled template. Like here: https://vuejs.org/v2/guide/render-function.html#Template-Compilation

Hydration doesn't add additional carriage return (%0D) characters to rendered content.

Visually rendered content doesn't have any unnecessary spaces.

What is actually happening?

Line feeds, carriage returns and whitespaces remain in compiled code and on top of that render differently after SSR hydration.

Hydration adds additional carriage return (%0D) characters to rendered content.

Visually rendered content has unnecessary spaces after SSR hydration (but not before).

This behavior can be observed here: https://workaline.com/collection/vue (it looks fine before hydration kicks in)

Image explaining it a little bit more:

crlf

Configs:

Note: I've tried changing vue-loader compilerOptions.preserveWhitespace to different values - but that didn't changed anything.

webpack.base.config.js

/*------------------------------------*\
  Imports
\*------------------------------------*/
const NODE_ENV = process.env.NODE_ENV || 'development';
const path = require('path');
const postCSSPresetEnv = require('postcss-preset-env');


/*------------------------------------*\
  Options
\*------------------------------------*/
const browsersList = [
  '> 1%',
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 40',
  'chrome >= 40',
  'safari >= 7',
  'ios >= 7',
  'android >= 4.4',
]


/*------------------------------------*\
  Base
\*------------------------------------*/
var baseConfig = {

  mode: NODE_ENV,

  devtool: 'cheap-module-eval-source-map',

  module: {

    rules: [

      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          compilerOptions: {
            preserveWhitespace: false
          }
        }
      },

      {
        test: /\.js$/,
        include : path.join(__dirname, '/src'),
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true,
              compact: true,
              presets: [
                [
                  '@babel/preset-env', {
                    targets: {
                      browsers: browsersList,
                    }
                  },
                ],
              ],

            },
          },
        ],
      },

      {
        test: /\.scss$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'vue-style-loader',
          },
          {
            loader: 'css-loader',
          },
          {
            loader: 'sass-loader',
            options: {
              outputStyle: 'compressed',
            },
          },
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => [
                postCSSPresetEnv({
                  browsers: browsersList,
                }),
              ]
            },
          },

        ],
      },

      {
        test: /\.css$/,
        use: [
          {
            loader: 'vue-style-loader',
          },
          {
            loader: 'css-loader',
          },
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => [
                postCSSPresetEnv({
                  browsers: browsersList,
                }),
              ]
            },
          },

        ],
      },

      {
        test: /\.(png|jpe?g|gif|eot|svg|otf|ttf|woff|woff2)(\?\S*)?$/,
        use: [
          {
            loader: 'url-loader',
            query: {
              limit: 100000000,
            },
          },
        ],
      },

    ],

  },

};


/*------------------------------------*\
  Export
\*------------------------------------*/
module.exports = baseConfig;


webpack.client.config.js

/*------------------------------------*\
  Imports
\*------------------------------------*/
const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const WebpackCleanupPlugin = require('webpack-cleanup-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const NODE_ENV = process.env.NODE_ENV || 'development';


/*------------------------------------*\
  Import Base Config
\*------------------------------------*/
var baseConfig = require('./webpack.base.config.js');


/*------------------------------------*\
  Client
\*------------------------------------*/
var clientConfig = webpackMerge(baseConfig, {

  entry: {
    app: path.join(__dirname, '/src/entry.client.js'),
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"' + NODE_ENV + '"',
        VUE_ENV: '"client"',
      }
    }),
    new VueLoaderPlugin(),
    new VueSSRClientPlugin(),
  ],


});


/*------------------------------------*\
  Development
\*------------------------------------*/
if (NODE_ENV === 'development') {

  clientConfig.output = {
    path: path.join(__dirname, '/dist'),
    publicPath: '/dist/',
    filename: '[name].[hash].js',
  };

}


/*------------------------------------*\
  Production
\*------------------------------------*/
if (NODE_ENV === 'production') {

  clientConfig.devtool = '';

  clientConfig.output = {
    path: path.join(__dirname, '/dist'),
    publicPath: '/dist/',
    filename: '[name].[hash].js',
  }

  clientConfig.plugins = (clientConfig.plugins || []).concat([

    new WebpackCleanupPlugin({
      preview: false,
    }),

    new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      openAnalyzer: false,
    }),

  ]);

}


/*------------------------------------*\
  Export
\*------------------------------------*/
module.exports = clientConfig;


webpack.server.config.js

/*------------------------------------*\
  Imports
\*------------------------------------*/
const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const packageJSON = require('../../package.json');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const VueSSRServerPlugin  = require('vue-server-renderer/server-plugin');
const NODE_ENV = process.env.NODE_ENV || 'development';


/*------------------------------------*\
  Import Base Config
\*------------------------------------*/
var baseConfig = require('./webpack.base.config.js');


/*------------------------------------*\
  Server
\*------------------------------------*/
var serverConfig = webpackMerge(baseConfig, {

  target: 'node',

  externals: Object.keys(packageJSON.dependencies),

  entry: path.join(__dirname, '/src/entry.server.js'),

  devtool: 'source-map',

  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'server.bundle.js',
    libraryTarget: 'commonjs2',
  },

  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"' + NODE_ENV + '"',
        VUE_ENV: '"server"',
      }
    }),
    new VueLoaderPlugin(),
    new VueSSRServerPlugin(),
  ],

});


/*------------------------------------*\
  Export
\*------------------------------------*/
module.exports = serverConfig;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions