skip to Main Content

I have a webapp that uses the following tech stack :

  • Apache running on Amazon EC2 Instance
  • Django, serving via WSGI
  • Javascript compiled via webpack / babel

Things are working great on a desktop environment, but on mobile, it is completely non-functional. When I navigate to the home page, mobile browsers try to initiate a download rather than serving the page.

enter image description here

I’ve been beating my head against the wall for a few days trying to figure out what is going on, but I don’t have any leads.

Here is my webpack.config.js, since I think that’s the most likely place for a problem :

const path = require('path');
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const BundleTracker = require('webpack-bundle-tracker');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const SentryCliPlugin = require('@sentry/webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

const devMode = process.env.NODE_ENV !== 'production';
const hotReload = process.env.HOT_RELOAD === '1';


const styleRule = {
  test: /.(sa|sc|c)ss$/,
  use: [
    MiniCssExtractPlugin.loader,
    { loader: 'css-loader', options: { sourceMap: true } },
    {
      loader: 'postcss-loader',
      options: {
        plugins: () => [autoprefixer({
          overrideBrowserslist: [
            'last 2 Chrome versions',
            'not Chrome < 60',
            'last 2 Safari versions',
            'not Safari < 10.1',
            'last 2 iOS versions',
            'not iOS < 10.3',
            'last 2 Firefox versions',
            'not Firefox < 54',
            'last 2 Edge versions',
            'not Edge < 15',
          ],
        })],
      },
    },
    'sass-loader',
  ],
};

const jsRule = {
  test: /.js$/,
  include: [
    path.resolve('./'),
  ],
  exclude: [/node_modules/, /lib/],
  use: [
    'babel-loader',
    {
      loader: 'eslint-loader',
      options: {
        fix: true,
        presets: ['@babel/preset-es2015'],
      },
    },
  ],
};

const assetRule = {
  test: /.(jpg|png|woff(2)?|eot|ttf|svg)$/,
  loader: 'file-loader',
};

const plugins = [
  new webpack.ProvidePlugin({
    'window.jQuery': 'jquery',
    jQuery: 'jquery',
    $: 'jquery',
  }),
  new BundleTracker({ filename: './webpack-stats.json' }),
  new MiniCssExtractPlugin({
    filename: devMode ? '[name].css' : '[name].[hash].css',
    chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
  }),
  new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }),
  new webpack.HotModuleReplacementPlugin(),
  new CleanWebpackPlugin(),
  // new CleanWebpackPlugin(['./static/dist']),
  new CopyWebpackPlugin([
    { from: './static/src/images/**/*', to: path.resolve('./static/dist/images/[name].[ext]'), toType: 'template' },
  ]),
];

if (devMode) {
  styleRule.use = ['css-hot-loader', ...styleRule.use];
} else {
  plugins.push(
    new webpack.EnvironmentPlugin(['NODE_ENV']),
  );
  if (process.env.SENTRY_DSN) {
    plugins.push(
      new SentryCliPlugin({
        include: '.',
        release: process.env.SOURCE_VERSION,
        ignore: ['node_modules', 'webpack.config.js'],
      }),
    );
  }
}

module.exports = {
  context: __dirname,
  entry: {
    app: './wzapp/global_web_source/app.js',
    main: './main/web_src/app.js',
    coop: './coop/web_src/app.js',
    wdns: './wdns/web_src/app.js',
  },
  output: {
    path: path.resolve('./static/dist/'),
    filename: '[name]-[hash].js',
    publicPath: hotReload ? 'https://localhost:8080/' : '',
  },
  devtool: devMode ? 'cheap-eval-source-map' : 'source-map',
  devServer: {
    hot: true,
    quiet: false,
    https: {
      key: 'server.key',
      cert: 'server.crt',
    },
    headers: { 'Access-Control-Allow-Origin': '*' },
  },
  module: { rules: [jsRule, styleRule, assetRule] },
  plugins,
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: true, // set to true if you want JS source maps
      }),
      new OptimizeCSSAssetsPlugin({}),
    ],
    splitChunks: {
      cacheGroups: {
        commons: {
          name: 'commons',
          chunks: 'initial',
          minChunks: 2,
        },
      },
    },
    // splitChunks: {
    //   cacheGroups: {
    //     commons: {
    //       test: /[\/]node_modules[\/]/,
    //       name: 'vendor',
    //       chunks: 'initial',
    //     },
    //   }
    // }
  },
};

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to @yoomama for pointing me in the right direction. It turns out the issue was with my wsgi configuration, and some headers that mobile sites needed. I modified my wsgi.py to add a Middleware config to fix it, as follows :

    from django.core.wsgi import get_wsgi_application
    
    class Middleware(object):
        def __init__(self, app):
            self.app = app
    
        def __call__(self, environ, start_response):
    
            def custom_start_response(status, headers, exc_info=None):
                headers.append(('Content-Type', "text/html; charset=ISO-8859-1"))
                headers.append(('Cache-Control', "no-cache"))
                return start_response(status, headers, exc_info)
    
            return self.app(environ, custom_start_response)
    
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'wzapp.settings')
    
    app = get_wsgi_application()
    
    application = Middleware(app)


  2. Scratch all of my previous comments. Here is a curl request:

    curl -vvv apps-staginy.uszel 
    > 
    < HTTP/1.1 200 OK
    < Date: Mon, 27 Jan 2020 02:37:18 GMT
    < Content-Type: <wsgirequest: get '/'>
    < Content-Length: 2821
    < Connection: keep-alive
    < Server: Apache/2.4.41 () PHP/5.4.16 mod_wsgi/4.6.8 Python/3.7
    < Upgrade: h2,h2c
    < X-Frame-Options: SAMEORIGIN
    

    Notice the Content-Type… Something is wrong with your Apache configuration. I believe it’s because Django can’t serve subdomains unless you download a package. I’m on Safari OSX and it downloaded file but on Google Chrome it didn’t.

    Edit 1: Here is your current website not on a subdomain. I think your Babel configuration is supposed to redirect me to this

    < HTTP/1.1 301 Moved Permanently
    < Date: Mon, 27 Jan 2020 02:44:32 GMT
    < Content-Length: 0
    < Connection: keep-alive
    < expires: -1
    < location: https://www.wizely.us/
    < x-seen-by: gv/XVF9HsGpk8A2KWukUzOwfbs+7qUVAqsIx00yI78k=,BTzakfJUbU/4CBguyutVdw7fAhTBvcXRsSG6ZgbhvQs=,1wy2ILu/S4rlWT/R4rqCrUa3k5dNGUFx8V61B2dxvEc=,LWZ6Tylfijl32cnmU7+qjL+1H2A1RrmXQxSZltmzRpFGp/J3MBzgzU8QHrQuh4zQ,nxVDKlf5lZ8xGkFSmm2J1uKPSHBdc9xPwY1nZvlDEaqXDJjWFZJonuG0MMyDy/pKSJ1s0Omld5LJBBda8omfzA==
    < cache-control: no-cache
    < content-language: en
    < X-Wix-Request-Id: 1580093072.79516762495826127415
    < 
    * Connection #0 to host wizely.us left intact
    * Closing connection 0
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search