Django Webpack Loader Breaking Vue Router Links - django

Short Version
When I visit localhost my django/vue app renders fine. But when I click into a link, rather than being brought to localhost/about I'm brought to http://localhost/http:/0.0.0.0:8080/about because of my webpack and vue.config.js settings.
Details
I have an application running (in docker-compose) Django on the backend and Vue on the frontend. The app uses django-webpack-loader and webpack-bundle-tracker to render the application in Django.
# Django settings.py
WEBPACK_LOADER = {
"DEFAULT": {
"CACHE": DEBUG,
"BUNDLE_DIR_NAME": "/bundles/",
"STATS_FILE": os.path.join(FRONTEND_DIR, "webpack-stats.json"),
}
}
# Django urls.py
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, re_path
from django.views.generic import TemplateView
urlpatterns = [
path("admin/", admin.site.urls),
re_path("^.*$", TemplateView.as_view(template_name="application.html"), name="app"),
]
if settings.DEBUG:
urlpatterns = (
urlpatterns
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
)
<!-- Template -->
{% load render_bundle from webpack_loader %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="/favicon.ico">
<title>My Website</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons">
</head>
<body>
<noscript>
<strong>We're sorry but this application doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
<app></app>
</div>{% render_bundle 'app' %}<!-- built files will be auto injected -->
</body>
</html>
// vue.config.js
const BundleTracker = require("webpack-bundle-tracker");
module.exports = {
publicPath:
process.env.NODE_ENV === "production"
? "https://example.com"
: "http://0.0.0.0:8080/",
outputDir: "./dist/",
chainWebpack: config => {
config.optimization.splitChunks(false);
config
.plugin("BundleTracker")
.use(BundleTracker, [{ filename: "webpack-stats.json" }]);
config.resolve.alias.set("__STATIC__", "static");
config.devServer
.public("http://0.0.0.0:8080")
.host("0.0.0.0")
.port(8080)
.hotOnly(true)
.watchOptions({ poll: 500 })
.https(false)
.headers({ "Access-Control-Allow-Origin": ["*"] });
}
};
When I fire up the application, visiting localhost works fine, but if I try to click one of the vuetify links, it brings me to http://localhost/http:/0.0.0.0:8080/about (presumably because that's the URL I've specified as the publicPath for the dev environment). If I replace localhost with http://0.0.0.0 I get the same undesired redirection to http://0.0.0.0/http:/0.0.0.0:8080/. However, if I visit localhost:8080 I can browse the app and links click through to their proper location (eg localhost:8080/about).
I tried removing my configuration of the publicPath but the Django application is unable to serve up the vue app when I do so: the app loads a blank page with a javascript error of SyntaxError: expected expression, got '<' in app.js. I assume that's because it's trying to load http://0.0.0.0/app.js and receiving the same template response that http://0.0.0.0 serves up.
So I think I have a few options:
1) Should I keep the default vue.config.js publicPath option, and configure django to serve up app.js from the proper location (and if so, what is that location?)
2) Can I configure vue router to use a different root URL from that specified in publicPath?
If this configuration isn't possible, I can switch over to having the SSR take place in Nuxt rather than Django, but I'm curious to learn more about what sort of configuration issue is at play here.

You can configure vue router to use a different root URL.
Just replace in router.js
base: process.env.BASE_URL,
With
base: '/',

I believe is resolved by adding
mode: "history",
to your router.js file.

Related

Build in production mode results in empty page while build in dev mode works perfectly (Angular 8)

In Development-mode (APS-WebAPI) the build works perfekt without errors (ng b --watch). When change to production-mode (ng b --aot OR ng b --prod) the page loads without error but results in an empty page. The Index.cshtml would generated by searching the *.js-files in the folder from the Homecontroller. This problem occurs since we upgrade from Angular-6 to Angular-8.
We would like to publish our changes and environment upgrade (Angular-8 & TypeScript 3.4.5). In Dev-mode (ng b --watch) we render the main.js / polyfills.js / runtime.js / styles.css / vendor.js / modules*.js to the Index.cshtml. This works perfectly.
When publishing with --aot or --prod we get all files with the ES5 and ES2015. In the same scheme we render that to the Index.cshtml. After loading the page, all files are found but the page is blank without an error. The files are all loaded like in the angular generated index.html
We use the following Index.cshtml, it`s generally the same for Dev- and Prod-Mode.
ConfigurationViewModel model = new ConfigurationViewModel();
var webPath = HttpRuntime.AppDomainAppVirtualPath;
var localPath = HostingEnvironment.MapPath(webPath);
var angularPath = Path.Combine(localPath ?? throw new InvalidOperationException(), "Map");
var angularDirectory = new DirectoryInfo(angularPath);
Prod-Mode
model.RuntimeJsEs5 = angularDirectory.GetFiles("runtime-es5*.js").Single().Name;
model.RuntimeJsEs2015 = angularDirectory.GetFiles("runtime-es2015*.js").Single().Name;
model.PolyfillsJsEs5 = angularDirectory.GetFiles("polyfills-es5*.js").Single().Name;
model.PolyfillsJsEs2015 = angularDirectory.GetFiles("polyfills-es2015*.js").Single().Name;
model.MainJsEs5 = angularDirectory.GetFiles("main-es5*.js").Single().Name;
model.MainJsEs2015 = angularDirectory.GetFiles("main-es2015*.js").Single().Name;
model.StylesCss = angularDirectory.GetFiles("styles.css").Single().Name;
<head>
....
<link rel="stylesheet" href="#Model.ConfigurationViewModel.StylesCss">
....
</head>
<body>
....
<script type="module" #src="#Model.ConfigurationViewModel.RuntimeJsEs2015"></script>
<script type="module" src="#Model.ConfigurationViewModel.PolyfillsJsEs2015"></script>
<script nomodule src="#Model.ConfigurationViewModel.RuntimeJsEs5"></script>
<script nomodule" src="#Model.ConfigurationViewModel.PolyfillsJsEs5"></script>
<script type="module" src="#Model.ConfigurationViewModel.MainJsEs2015"></script>
<script nomodule src="#Model.ConfigurationViewModel.MainJsEs5"></script>
....
</body>
Dev-Mode
model.RuntimeJsEs2015 = angularDirectory.GetFiles("runtime.js").Single().Name;
model.PolyfillsJsEs2015 = angularDirectory.GetFiles("polyfills.js").Single().Name;
model.MainJsEs2015 = angularDirectory.GetFiles("main.js").Single().Name;
model.StylesCss = angularDirectory.GetFiles("styles.css").Single().Name;
model.VendorJsEs2015 = angularDirectory.GetFiles("vendor.js").Single().Name;
<head>
....
<link rel="stylesheet" href="#Model.ConfigurationViewModel.StylesCss">
....
</head>
<body>
....
<script type="module" src="#Model.ConfigurationViewModel.RuntimeJsEs2015"></script>
<script type="module" src="#Model.ConfigurationViewModel.PolyfillsJsEs2015"></script>
<script type="module" src="#Model.ConfigurationViewModel.VendorJsEs2015"></script>
<script type="module" src="#Model.ConfigurationViewModel.MainJsEs2015"></script>
....
</body>
If necessary i would post also the angular.json later.
I would present my solution, if somebody has the same problem.
The "build-optimizer" from Angular induce the empty white page. The following github issue brougth me to the solution (https://github.com/angular/angular-cli/issues/8758). So if you disable the buildOptimizer in the the angular.json everything works perfectly.
FYI the angular issue 12112 points also to this problem (https://github.com/angular/angular-cli/issues/12112).

react django rendering same content

I'm working on Django-react project and having issue with rendering React component on Django server. To be precise, React always render me the same content even if I change it. I'm using Webpack, Babel-loader and running it on localhost.
project/templet/frontend/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Django-React</title>
</head>
<body>
<div id="app" class="columns"><!-- React --></div>
{% load static %}
<script type='text/javascript' src="{% static "frontend/main.js" %}"></script>
</body>
</html>
Entry point:
import ReactDOM from "react-dom";
import App from './components/App';
ReactDOM.render(<App/>, document.getElementById("app"));
Scripts in package.json:
"scripts": {
"dev": "webpack --mode development ./frontend/src/index.js --watch ./frontend/static/frontend/main.js",
"build": "webpack --mode production ./frontend/src/index.js --output ./frontend/static/frontend/main.js"
}
Babel config:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};
So, when I write some content in App component (eg. render div with "test") I can see it in my browser, but when I want to change it, and after refresing page, get the same content from div tag
From what i can understand from your question, When you first render a div with 'test' in it, it renders, but after that, further changes dont update.
Its because the javascript is not being updated on Django and you need to use collectstatic to sync the builds which is not very efficient.
The way to go is to use django-webpack-loader and webpack-bundle-tracker.
install webpack-bundle-tracker
npm install --save-dev webpack-bundle-tracker
install django-webpack-loader:
pip install django-webpack-loader
django-webpack-loader is a python package which injects link and script tag for the bundles which webpack generates dynamically.
webpack-bundle-tracker plugin emits necessary information about webpack compilation process to a json file so django-webpack-loader can consume it.
For webpack to track changes made in your App, You need to create a server that monitors changes in your React app and bundle your JS.
Note: We make use of a node server.
// Webpack Server
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const config = require('./webpack.server.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
inline: true,
historyApiFallback: true
}).listen(3000, '0.0.0.0', function (err, result) {
if (err) {
console.log(err)
}
console.log('Listening at 0.0.0.0:3000')
});
The config files used by webpack.server.js would be at webpack.server.config.js
// webpack.server.config.js
const path = require("path");
const BundleTracker = require('webpack-bundle-tracker');
module.exports = {
mode: 'development',
entry: {
main: './frontend/src/index.js',
devServer: 'webpack-dev-server/client?http://localhost:3000'
},
output: {
filename: "[name].js",
path: path.resolve('./frontend/static/frontend/bundles/'),
publicPath: 'http://localhost:3000/frontend/static/frontend/bundles/', // django-webpack-loader overrides django's STATIC_URL with this path
},
plugins: [
new BundleTracker({filename: './frontend/webpack-stats.json'}), // Pass the correct path to the WEBPACK_LOADER in django settings
],
devServer: {
contentBase: './frontend/static/frontend/bundles/',
},
};
Note that the server will by default keep the bundles in memory and
not write to disk
When the server is stopped, there would be no sign of the bundled files as they were not compiled to memory.
To build your files to memory in development, create another config file at webpack.dev.config.js
// webpack.dev.config.js
const path = require("path");
const BundleTracker = require('webpack-bundle-tracker');
module.exports = {
mode: 'development',
entry: {
main: './frontend/src/index.js',
},
output: {
filename: "[name].js",
path: path.resolve('./frontend/static/frontend/bundles/'),
},
plugins: [
new BundleTracker({filename: './frontend/webpack-stats.json'}), // Pass the correct path to the WEBPACK_LOADER in django settings
],
};
While to build your files for Production, create another config file at webpack.prod.config.js
// webpack.prod.config.js
const path = require("path");
const BundleTracker = require('webpack-bundle-tracker');
module.exports = {
mode: 'production',
entry: {
main: './frontend/src/index.js',
},
output: {
filename: "[name].js",
path: path.resolve('./frontend/static/frontend/dist/'),
},
plugins: [
new BundleTracker({filename: './frontend/webpack-stats-prod.json'}), // Pass the correct path to the WEBPACK_LOADER in django settings
],
};
In your Django settings;
import sys
import os
# Assuming this is your base directory
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Also assuming this is your base directory
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
# In development
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'), # Path to 'webpack-stats.json'
}
}
# In production
if not DEBUG:
WEBPACK_LOADER['DEFAULT'].update({
'BUNDLE_DIR_NAME': 'dist/',
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats-prod.json') # Path to 'webpack-stats-prod.json'
})
INSTALLED_APPS = (
...
'webpack_loader',
)
Your index.html should look like this now;
{% load render_bundle from webpack_loader %} <<< Add this.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Django-React</title>
</head>
<body>
<div id="app" class="columns">
<!-- React -->
</div>
{% render_bundle 'main' %} <<< Add this.
</body>
</html>
Now, Your package.json should look like this;
"scripts": {
"dev": "node ./webpack.server.js",
"build-dev": "webpack --mode development --config ./webpack.dev.config.js",
"build-prod": "webpack --mode production --config ./webpack.prod.config.js"
}
So, To develop with automatic bundling, just run:
npm run dev
To build your files to memory after the webpack server is stopped, just run:
npm run build-dev
And finally, to build with production optimizations, just run:
npm run build-prod
I tried to modify to your project, feel to adjust according to your project structure. Check the below referrences to guide you better. They helped me out!
References:
Let's modernize the way we handle frontend code with Django
Using Webpack transparently with Django + hot reloading React components as a bonus
Modern Django: Part 1: Setting up Django and React

How to enable swagger UI in AWS

I created the serverless application using .Net core and hosted in AWS. I am able to create swagger.json by publishing API documentation under API gateway.
I am looking for the documentation to create swagger UI for those APIs.
Is any possibility to view the swagger UI in AWS itself.
I do not think AWS built a swagger UI in one of their services. At least, I am not aware of it.
However, it is possible to easily create a swagger visualization using S3.
There is an article on Medium which explains this well. [1]
Basically, what you need to script is:
Creation of an S3 bucket with static website hosting
Downloading the static swagger UI resources from GitHub
Syncing the resources to the S3 bucket
Downloading the swagger.json from API Gateway [2]
Uploading the swagger.json to S3
Modify index.html to point at your swagger.json
These steps are laid out in detail in the Medium article. [1]
References
[1] https://medium.com/nirman-tech-blog/swagger-ui-for-aws-api-gateway-endpoints-a667f25f5a4b
[2] https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-export-api.html
You can easily host self-contained swagger-UI web site in S3.
Here is an example: https://iris-fhir-server.s3.amazonaws.com/swagger-ui.html
Github: https://github.com/intersystems-community/Swagger-IRIS-FHIR
It's essentially your OpenAPI yaml or json files plus single HTML page like:
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist#3/swagger-ui.css" >
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
.errors-wrapper {
display: none !IMPORTANT;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist#3/swagger-ui-bundle.js"> </script>
<script src="https://unpkg.com/swagger-ui-dist#3/swagger-ui-standalone-preset.js"> </script> <script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
"dom_id": "#swagger-ui",
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
validatorUrl: "https://validator.swagger.io/validator",
//url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Patient.yml",
urls: [
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Organization.yml", name: "Organization"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Patient.yml", name: "Patient"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Practitioner.yml", name: "Practitioner"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Condition.yml", name: "Condition"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Medication.yml", name: "Medication"},
{url: "https://iris-fhir-server.s3.amazonaws.com/openapi/Observation.yml", name: "Observation"}
],
"urls.primaryName": "Patient"
})
window.ui = ui
}
</script>
</body>
</html>

Heroku Deployment with Django: Webpack Bundle returns content of index.html instead of actual bundle

The application runs fine in development, but once in production the generated webpack bundle file is serving the contents of index.html and not all the bundled modules and dependencies.
Whenever I check the bundle file on the server, everything seems alright, but the same path is served differently on the client.
webpack.config.js
//require our dependencies
var path = require('path')
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')
module.exports = {
//the base directory (absolute path) for resolving the entry option
context: __dirname,
//the entry point we created earlier. Note that './' means
//your current directory. You don't have to specify the extension now,
//because you will specify extensions later in the `resolve` section
entry: [
'./assets/js/index'
],
output: {
path: path.resolve('./assets/bundles/'),
filename: "[name]-[hash].js"
},
plugins: [
//tells webpack where to store data about your bundles.
new webpack.NoErrorsPlugin(), // don't reload if there is an error
new BundleTracker({filename: './webpack-stats.json'}),
//makes jQuery available in every module
new webpack.ProvidePlugin({
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
],
module: {
loaders: [
// we pass the output from babel loader to react-hot loader
{
test: [/\.js$/, /\.es6$/, /\.jsx?$/],
exclude: /node_modules/,
loaders: ['babel'],
},
{ test: /\.css$/, loader: "style-loader!css-loader" }
]
},
resolve: {
//tells webpack where to look for modules
modulesDirectories: ['node_modules'],
//extensions that should be used to resolve modules
extensions: ['', '.js', '.jsx']
}
}
Served Content:
Uncaught SyntaxError: Unexpected token <
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!--<title></title>-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="/static/jquery/dist/jquery.js"></script>
<script type="text/javascript" src="/static/materialize-css/dist/js/materialize.min.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/javascript" src="/static/assets/bundles/main-210eb139915d8d6abedf.js" ></script>
</body>
Thanks in advance.

tinymce django not showing up

I know this question have been asked here so many times, but i just cant show up Tinymce in my admin's flatpages. I don't know where I'm missing or doing something wrong. Please help me out where I'm going wrong.
The javascript file is in:
C:\Users\Kakar\web\cms\static\js\tinymce\tinymce.min.js
urls.py:
(r'^tiny_mce/(?P<path>.*)$', 'django.views.static.serve', { 'document_root': 'C:/Users/Kakar/web/cms/static/js/tinymce' }),
In my templates dir i have another admin folder, which have the change_form.html:
and right after {{ media }}:
<script type="text/javascript" src="/tinymce.min.js"></script>
<script type="text/javascript">
tinyMCE.init({
mode: "textareas",
theme: "simple"
});
</script>
In the firebug it says:
ReferenceError: tinyMCE is not defined
tinyMCE.init({
Please help me out. Thank you.
Your url for you tinymce script is currently pointing to http://yoursite/tiny_mce/ because of this: (r'^tiny_mce/... but the script you have included would attempt to GET tinymce.min.js from http:/yoursite/tinymce.min.js because you have not included the /tiny_mce/tinymce.min.js in front of it. If your tinymce.min.js is in a subdirectory you would need to include the path to it as follows <script type="text/javascript" src="/tiny_mce/(pathtodirectory)/tinymce.min.js"></script>