public/index.html tuning in vue-cli - vue-cli

Is it possible to configure injected files places in public/index.html?
I want to generate a django template instead of simple html file provided, it could look like this:
{% extends 'base.html' %}
{% block header_extra %}
<!-- app.css -->
{% endblock %}
{% block js_extra %}
<!-- app.js, chunk-vendors.js, etc -->
{% endblock %}
{% block main_content %}
<div id="app"></div>
{% endblock %}

I've found how to do it, first it's required to disable files injecting in vue.config.js:
configureWebpack: config => {
config.plugins.forEach((plugin) => {
if(plugin.constructor.name === 'HtmlWebpackPlugin') {
plugin.options.inject = false;
plugin.options.minify.collapseWhitespace = false;
}
});
}
For the next it's needed to insert js / css files using underscore templating.
Here I'm prepending vue before file names, cause I collect static with django.
{% extends 'base.html' %}
{% load static %}
{% block header_extra %}
<% htmlWebpackPlugin.files.css.forEach((fileName) => { %>
<link rel="stylesheet" href="{% static 'vue<%= fileName %>' %}">
<% }) %>
{% endblock %}
{% block js_extra %}
<% htmlWebpackPlugin.files.js.forEach((fileName) => { %>
<script src="{% static 'vue<%= fileName %>' %}"></script>
<% }) %>
{% endblock %}
{% block main_content %}
<div id="app"></div>
<!--
<pre id="config">
<%= JSON.stringify(htmlWebpackPlugin, null, 2) %>
</pre>
-->
{% endblock %}
Then, cause I have to collect static to static/vue directory, in settings.py I added a new dir:
STATICFILES_DIRS = [
# vue is an additional subdirectory for vue static
('vue', os.path.join(BASE_DIR, '../frontend/dist')),
]
Also it's needed to have an access to the vue generated template from django, so in settings.py:
TEMPLATES = [
# ...
# 'frontend' is the vue project directory name,
# so you should be able to specify template like this:
# template_name='dist/index.html'
{'DIRS': ['frontend']}
# ...
]

Thanks
If someone prefers the webpack chain way:
chainWebpack: (config) => {
config.plugins.values().forEach( p => {
if (p.get('plugin').name === 'HtmlWebpackPlugin') {
// console.log(p.get('args'))
p.tap(args => [ merge(args[0], {
inject: false,
})]);
// console.log(p.get('args'))
}
})
}

Related

How can I separate header and footer in twig in Node.Js

I am trying to dynamic header and footer page but I cannot success. I tried many ways but the header is not loading and I cannot find any sample for Node.Js. No errors occurs but only body content is loaded. All files are at the same directory.
Here the codes are I am tried to.
layout.twig
<!doctype html>
<html lang="en-US">
..
<body>
<header>
<!-- HEADER -->
{% block header %}{% endblock %} //Also tried here in index.
</header>
{% block body %}{% endblock %}
</body>
</html>
index.twig
{% extends 'layout.twig' %}
{% block body %}
<body>
<header>
<!-- HEADER -->
{% block header %}{% endblock %} //Also tried here in layout.
</header>
...
{% endblock %}
header.twig
{% extends 'index.twig' %} //Also tried with {% extends 'layout.twig' %}
{% block header %}
<div class="header js-header js-dropdown">
<div class="container">
...
{% endblock %}
footer.twig is same with header.
EDIT:
Delete extend tags which include on layout.twig and it's solved.

Include script only once

I am building some twig modules that require specific javascript to work.
A javascript file is an asset that can be included as follows:
<script src="{{ asset('what/ever/hello.js') }}">
All cool so far, but knowing that:
Those modules may or may not be present on the final rendered page.
Those modules may appear more than once on the same page.
I don't want to include the javascript in all pages, only when at least one instance of the module that requires it is present.
If I add the script to the module twig file, and if the module is used multiple times, it will result in my page containing multiple calls to the same script.
How can I approach this case?
You can work with an extension to keep track of the scripts you want included,
<?php
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension {
protected $scripts = [];
public function getFunctions() {
return [
new \Twig\TwigFunction('get_scripts', [ $this, 'getScripts']),
new \Twig\TwigFunction('add_script', [ $this, 'addScript']),
];
}
public function getScripts() {
return $this->scripts;
}
public function addScripts($script) {
if (!in_array($script, $this->getScripts()) $this->scripts[] = $script;
}
}
Just some mock-up modules
{% do add_script('modules/module_a.js') %}
<h1>Module A</h1>
{% do add_script('modules/module_b.js') %}
<h1>Module B</h1>
Just a simple base template
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
{% block content %}
{% endblock %}
{% for script in get_scripts() %}
<script src="{{ asset(script) }}"></script>
{% endfor %}
</body>
</html>
Just a simple child template
{% extends "base.html" %}
{% block content %}
{% incude "modules/module_a.html" %}
{% incude "modules/module_b.html" %}
{% incude "modules/module_a.html" %}
{% incude "modules/module_b.html" %}
{% endblock %}
This would output something like
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<h1>Module A</h1>
<h1>Module B</h1>
<h1>Module A</h1>
<h1>Module B</h1>
<script src="js/modules/module_a.js"></script>
<script src="js/modules/module_b.js"></script>
</body>
</html>

Cannot resolve nunjucks template

Created a simple script to attempt to render a nunjucks template (Both the contact content and layout template are in the src directory:
let fs = require('fs');
let nj = require('nunjucks');
var contact = fs.readFileSync('./src/contact.html','utf8');
nj.configure('src');
let result = nj.render(contact);
console.log(result);
The contact content looks like this:
{% set title = 'Contact' %}
{% extends '_layout.html' %}
{% block content %}
<h1>Test Template</h1>
{% endblock %}
The layout template looks like this:
<!DOCTYPE>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
When running the script it throws:
Error: template not found: {% set title = 'Contact' %}
{% extends '_layout.html' %}
{% block content %}
<h1>Test Template</h1>
{% endblock %}
I was using the API wrong. Instead of reading in the file and telling Nunjucks to render it do this:
nj.configure('src');
let result = nj.render('contact.html');
Bot the contact.html and _template.html files are in the src directory. Almost too easy :)

Adding Bootstrap and a logo png to Apostrophe CMS

I am simply trying to add a bootstrap.min.css file with its corresponding bootstrap.min.js file to an Apostrophe CMS project. I have no idea how to simply add a static resource. I have the following in my app.js
'apostrophe-assets': {
stylesheets: [
{
name: 'bootstrap.min',
minify: false
},
{
name: 'site'
}
],
scripts: [
{
name: 'bootstrap.min',
minify: false
}
]
}
but alas, it does nothing. I have removed the .min versions as well and tried those, still nothing.
On that note, I need to be able to link to a .png that will be used in my navbar, but I have no idea where to store any static resources for the website.
Is there a place I can just drop static files that I don't want pushed as apostrophe-assets so they are rendered and consumed properly?
I am the lead developer of Apostrophe at P'unk Avenue.
For this to work, Apostrophe needs the files to be located at:
lib/modules/apostrophe-assets/public/css/bootstrap.min.css
And:
lib/modules/apostrophe-assets/public/js/bootstrap.min.js
Within your project (don't copy them into node_modules). You create your own lib/modules/apostrophe-assets folder within your own project, to parallel the one in the apostrophe npm module.
This is as documented here in the tutorials on pushing assets.
(If you have trouble pushing the CSS file, try renaming it with a .less extension and let me know you had to do that. It ought to be unnecessary though.)
Of course there is also nothing keeping you from overriding any of the blocks in outerLayoutBase.html in your own templates to insert script and link tags, but that shouldn't be necessary. If you follow the practice I'm recommending your files will minify with everything else in production.
I've used the apostrophe-assets module to push css and js files the same approach as provided by #boutell. For pushing js files it's ok, but for css I've got a parse error related to bootstrap css. So it's because the apostrophe tries to compile it into css whereas it is already css.
To solve this problem I've override the outerLayot.html Nunjucks template. So basically in the file
node_modules/lib/modules/apostrohpe-templates/views/outerLayout.html, we have:
{% extends "outerLayoutBase.html" %}
Which itself extends the outerLayoutBase.html
node_modules/lib/modules/apostrohpe-templates/views/outerLayoutBase.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
{{ apos.assets.stylesheets(data.when) }}
{% block standardHead %}
<meta name="viewport" content="width=device-width, initial-scale=1">
{% endblock %}
{% block extraHead %}
{% endblock %}
</head>
<body class="{% block bodyClass %}{% endblock %}">
{% block apostropheMenu %}
{{ apos.adminBar.output() }}
{% endblock %}
{% if data.user %}
<div class="apos-ui">
<div class="apos-context-menu-container">
{{ apos.pages.publishMenu({ publishMenu: data.publishMenu, page: data.page, piece: data.piece, bottom: true }) }}
{{ apos.pages.menu({ contextMenu: data.contextMenu, page: data.page, bottom: true })}}
</div>
</div>
{% endif %}
<div class="apos-refreshable" data-apos-refreshable>
{% block beforeMain %}{% endblock %}
<a name="main"></a>
{% block main %}{% endblock %}
{% block afterMain %}{% endblock %}
</div>
{{ apos.assets.templates(data.when) }}
{{ apos.assets.scripts(data.when) }}
<script type="text/javascript">
{{ data.js.globalCalls }}
{{ data.js.reqCalls }}
</script>
{% block extraBody %}
{% endblock %}
</body>
</html>
Here I have used {% block extraHead %}{% endblock %} block and overrided it into a new file which is:
/lib/modules/apostrohpe-templates/views/outerLayout.html
{% extends "outerLayoutBase.html" %}
{% block extraHead %}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
{% endblock %}
In the above file is included CDN of bootstrap css and works as expected. Note the path of this new file. The lib folder is under the root folder not the node_modules.

Extending twig blocks in a complicated scenario

Let's say I have these twig templates:
base.twig
{# base.twig #}
<html>
<head>
{% include 'head_js.twig' %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
head_js.twig
{# head_js.twig #}
{% block headJS %}
<script src='/js/some-script.js'></script>
{% block headJSExtra %}{% endblock %}
{% endblock %}
page.twig (the one loaded by the controller)
{# page.twig #}
{% extends base.twig %}
{% block content %}
<p>Widget 1</p>
{% include 'widget.twig' with { name: 'foo' } %}
<p>Widget 2</p>
{% include 'widget.twig' with { name: 'bar' } %}
{% endblock %}
widget.twig
{# widget.twig #}
{% if wigetAlreadyIncluded is not defined %}
{% block headJSExtra %}
{{ parent() }}
<script src='/js/widget.js'></script>
{% endblock %}
{% set widgetAlreadyIncluded = true %}
{% endif %}
<p>My name is {{ name }}</p>
This code doesn't work (can't use parent() in widget.twig as it's not extending or using any template), but it should illustrate what I'm trying to achieve. The basic idea is:
In order to work, widget.twig requires a js library to be loaded in as a tag in the .
The widget can be rendered several times in one page.
Other widgets should be able to also add their own tags in the in this fashion, but they shouldn't override previous added tags (they should be appended).
I don't want to add more than once any tag required by any widget found in the page.
Any ideas on how can I achieve this would be greatly appreciated. I've read two SO related questions with no luck at all.
https://stackoverflow.com/a/29132604/4949663
https://stackoverflow.com/a/18160977/4949663
I finally got a good answer in the twig github issue tracker.
https://github.com/twigphp/Twig/issues/2275

Resources