Vue + Webpack build show blank page
Asked Answered
C

5

9

I have some problem with vue application + webpack. When I run npm run dev everything went smooth. When I go for production mode, npm run build, the build process completed. But when I open the dist index.html or copy the bundled package with index.html to shared hosting public_html folder it just show blank.

below is my setup:

package.json

{
  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "build": "node build/build.js"
  },
  "dependencies": {
    "axios": "^0.17.1",
    "bootstrap": "^4.0.0",
    "jquery": "^3.3.1",
    "popper.js": "^1.12.9",
    "vue": "^2.5.2",
    "vue-router": "^3.0.1",
    "vuex": "^3.0.1"
  },
  "devDependencies": {
    "autoprefixer": "^7.1.2",
    "babel-core": "^6.22.1",
    "babel-helper-vue-jsx-merge-props": "^2.0.3",
    "babel-loader": "^7.1.1",
    "babel-plugin-syntax-jsx": "^6.18.0",
    "babel-plugin-transform-object-rest-spread": "^6.26.0",
    "babel-plugin-transform-regenerator": "^6.26.0",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-plugin-transform-vue-jsx": "^3.5.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-stage-2": "^6.22.0",
    "chalk": "^2.0.1",
    "compression-webpack-plugin": "^1.1.6",
    "copy-webpack-plugin": "^4.0.1",
    "cross-env": "^5.1.3",
    "css-loader": "^0.28.0",
    "extract-text-webpack-plugin": "^3.0.0",
    "file-loader": "^1.1.4",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "html-webpack-externals-plugin": "^3.6.0",
    "html-webpack-plugin": "^2.30.1",
    "node-notifier": "^5.1.2",
    "node-sass": "^4.7.2",
    "optimize-css-assets-webpack-plugin": "^3.2.0",
    "ora": "^1.2.0",
    "portfinder": "^1.0.13",
    "postcss-import": "^11.0.0",
    "postcss-loader": "^2.0.8",
    "postcss-url": "^7.2.1",
    "precss": "^3.1.0",
    "rimraf": "^2.6.0",
    "sass-loader": "^6.0.6",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "style-loader": "^0.20.1",
    "uglifyjs-webpack-plugin": "^1.1.1",
    "url-loader": "^0.5.8",
    "vue-loader": "^13.3.0",
    "vue-style-loader": "^3.0.1",
    "vue-template-compiler": "^2.5.2",
    "webpack": "^3.6.0",
    "webpack-bundle-analyzer": "^2.9.0",
    "webpack-dev-server": "^2.9.1",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 6.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

webpack file

config/index.js

'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.

const path = require('path')

module.exports = {
  dev: {

    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {},

    // Various Dev Server settings
    host: 'localhost', // can be overwritten by process.env.HOST
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: false,
    errorOverlay: true,
    notifyOnErrors: true,
    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-


    /**
     * Source Maps
     */

    // https://webpack.js.org/configuration/devtool/#development
    devtool: 'cheap-module-eval-source-map',

    // If you have problems debugging vue-files in devtools,
    // set this to false - it *may* help
    // https://vue-loader.vuejs.org/en/options.html#cachebusting
    cacheBusting: true,

    cssSourceMap: true
  },

  build: {
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: './',

    /**
     * Source Maps
     */

    productionSourceMap: false,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',

    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],

    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  }
}

webpack.base.conf.js

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(scss)$/,
        use: [{
          loader: 'style-loader', // inject CSS to page
        }, {
          loader: 'css-loader', // translates CSS into CommonJS modules
        }, {
          loader: 'postcss-loader', // Run post css actions
          options: {
            plugins: function () { // post css plugins, can be exported to postcss.config.js
              return [
                require('precss'),
                require('autoprefixer')
              ];
            }
          }
        }, {
          loader: 'sass-loader' // compiles SASS to CSS
        }]
      }
    ]
  },
  node: {
    // prevent webpack from injecting useless setImmediate polyfill because Vue
    // source contains it (although only uses it if it's native).
    setImmediate: false,
    // prevent webpack from injecting mocks to Node native modules
    // that does not make sense for the client
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0, shrink-to-fit=no">
    <title>Vue Application</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

main.js

import Vue from 'vue'
import App from './App.vue'
import store from './vuex/store'
import router from './router/router'
import helper from './helper'
import './assets/styles/main.scss'

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

App.vue

<template>
  <div id="app">
    <div id="wrapper">
  <!-- the router outlet, where all matched components would be viewed -->
  <!-- A named view, 'header' -->
    <router-view name="header"></router-view>
    <div class="clearfix"></div>
    <!-- A named view, 'dashboard' -->
      <router-view name="dashboard"></router-view>
    <!-- A named view, 'content' -->
    <router-view name="content"></router-view>
    <!-- A named view, 'footer' -->
    <router-view name="footer"></router-view>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
}
</script>

My primary suspect is there is something wrong with my asset configuration on webpack, so here is my folder structure in case it'll help.

src
  assets
    styles
      main.scss
  App.vue
  main.js

Sorry before if I can not show any further code, thanks.

Campbell answered 2/2, 2018 at 8:19 Comment(0)
R
10

I assume that you are running your production on a sub directory from the root project folder, e.g. http://example.com/folder.

If you project is in the folder sub-directory, you will need to configure the assetsPublicPath in config/index.js for the build property.

Example:

build: {
  assetsPublicPath: '/folder/'
}

Also, your routes file should have the base property set to:

export default new VueRouter({
  base: '/folder/'
})

See more here.


Upon gathering more data from you, it could be the configuration on your host that is loading the wrong page.

For Apache, your Alias or vhost should be pointed at the dist directory. For example (my own use case)

Alias /foo /var/www/htdocs/foo/dist
Resent answered 2/2, 2018 at 8:28 Comment(3)
Hi, thanks for quick response. well I've try but still no luck. If I'm looking on the page source and inspect the html element I can cleary see the script has been load to the bundled.js but when I look at the div#app, the child element is blank on routerview part. any idea?Campbell
Are you running on a Linux web server? You have to configure your directory to point to the dist folder. For example, your alias or vhost should point to /var/www/html/your-project/distResent
Configuring base property on the router worked for me. Thanks!Hiatt
T
4

In my case all I has to do is add a redirect in router.js
{ path: "/index.html", redirect: "/" }

Terrence answered 22/12, 2018 at 22:11 Comment(0)
B
1

I had this same problem. I found a solution (I think it was here on SO, but I don't remember and can't find it again). The solution was to explicitly declare the publicPath variable in vue.config.js:

module.exports = {
publicPath: "",
chainWebpack: config => {
    config.plugin("html").tap(args => {
        args[0].title = "My Vue App";
        return args;
    });
}

};

It worked, but I wondered why it worked, so I did some digging and, in the vue-cli documentation, I learned that the publicPath variable dictates the BASE_URL environment variable. It defaults to "/", so if you're running your Vue app in a root directory, it's unnecessary. If, however, as I was doing in my project, you're running it from a subdirectory like domain.com/appdir/index.html it will show a blank page because it's trying pull things from the "/" path (e.g.: domain.com/ )

Becoming answered 2/3, 2020 at 11:6 Comment(0)
E
0

In my scenario I use <template>, I had to enable runtimeCompiler inside my vue.config.js.

runtimeCompiler

Exasperation answered 12/11, 2019 at 11:22 Comment(0)
C
0

This worked for me: in router/index.js add

{
    path: '*',
    name: 'catchAll',
    component: Home
}

at the end of paths

Clean answered 25/2, 2020 at 14:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.