Is it possible to create a bundle with Rollup that injects HTML from a template? - html

I'm trying to build a IIFE (immediately-invoked function expression) bundle using Rollup.
I would like to bundle all together my JS, CSS, and then some HTML which the Javascript depends on. Check this image to get an idea:
Is there a way to tell Rollup that my input (entry point) is seguro-vida-hipoteca.js, and have this file import my SCSS and HTML so it will be automatically injected when somebody uses my library?
That would be, the resulting CSS in the head, and the HTML to some div that I would expect to exist in the dom, or just at the end of body.

Is there a way to tell Rollup that my input (entry point) is seguro-vida-hipoteca.js?
Sure, that's what the input option is for.
Injecting Sass in the head is easily accomplishable with plugins such as rollup-plugin-postcss:
// rollup.config.js
import postcss from 'rollup-plugin-postcss';
export default {
// ...
plugins: [
postcss(),
],
}
import './style.scss'; // Now each stylesheet you import will
// be injected to <head>
About injecting/appending html, that is something you would normally do in your code and not through a plugin, although you can take advantage of Rollup to load template.html as a string (for example by using rollup-plugin-html):
import html from "rollup-plugin-html";
export default {
// ...
plugins: [
html({
include: "**/*.html",
}),
],
}
import template from './template.html';
document.querySelector('#mydiv').innerHTML = template;
Side note
This seems to be a good use case for WebComponents. More info here.

Related

purgecss can't recognize conditional classes

So I'm using TailwindCSS for a WP theme I'm developing.
I ran into an issue in creating the production grade theme files because, from how I understand the problem, purgecss can't recognize conditional classes used on template parts. For example, let's say I created a template part called "business-card.php" where I pass it a variable type (using set_query_var / get_query_var):
page-about.php
set_query_var('type', 'A');
get_template_part('template-parts/content/business', 'card');
set_query_var('type', 'B');
get_template_part('template-parts/content/business', 'card');
businesss-card.php
$type = get_query_var('type')
<div class="<?php echo type == 'A' ? 'text-color-A' : 'text-color-B' ?>">
--- insert some content here ---
</div>
So there will be two divs, one will have a text-color-A class, the other will have a text-color-B, both were created using a config file(rather than included in the base tailwind theme). This is fine in development -- since tailwind does actually create the utility color classes from the config file. But for some reason, when it's in production (i.e. purged & minified), it doesn't have those utility classes -- which were only used in the template part as conditional classes (and not in any other file).
PurgeCSS is intentionally very naive in the way it looks for classes in your HTML. It doesn't try to parse your HTML and look for class attributes or dynamically execute your JavaScript — it simply looks for any strings in the entire file that match this regular expression:
/[^<>"'`\s]*[^<>"'`\s:]/g
That means that it is important to avoid dynamically creating class strings in your templates with string concatenation, otherwise PurgeCSS won't know to preserve those classes.
So do not use string concatenation to create class names:
<div :class="text-{{ error ? 'red' : 'green' }}-600"></div>
Instead, dynamically select a complete class name:
<div :class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>
As long as a class name appears in your template in its entirety, PurgeCSS will not remove it.
See the docs for more details:
Writing purgeable HTML
If you are using Tailwind 2.0+ you can configure whitelisted classes that will be ignored by purge CSS directly inside of your tailwind.config.js file.
An example of my own code where I whitelist the class text-ingido-400 can be seen below
// tailwind.config.js
module.exports = {
purge: {
content: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
options: {
safelist: ['text-indigo-400']
}
} ,
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
For more information you can check out the relevant documentation located at:
https://tailwindcss.com/docs/optimizing-for-production
You can use the PurgeCSS whitelist option to add those classes.
const purgecss = new Purgecss({
//... Your config
whitelist: ['text-color-A', 'text-color-B', 'etc']
})
Or the whitelistPatterns (Regex match)
whitelistPatterns: [/^text-color/], // All classes starting with text-color
You can find more information here
If you define your class names in a variable above where you want to use them it works akin to safe listing them in Tailwind or whitelisting them in PurgeCSS, is potentially easier to maintain, and works good in a pinch if you have a small number of possbile dynamic class names.
var classes =`grid-cols-1 grid-cols-2 grid-cols-3 grid-cols-4`
return (
<div className={`grid grid-cols-${items['grid-cols']}`}>
</div>
)
For some tailwindcss class, you can use inline style instead.
Inline style allow you to use dynamic value, like <div style="padding-left:{indent}rem">.
I think it works in php also. More details can be found here

How to execute different sass files based on a css class?

I am wondering how can I can include a different sass file (theme) based on a certain class?
Now we got 3 apps which all have an unique css class for its styling (.app1 {.background-color: red;})
Now i want to include sass framework and seperate all the css/sass per app label. In order to achieve this we define a base.scss. In this scss we want to reach this:
if .app1 then execute app1.scss
else if .app2 then execute app2.scss
else if .app3 then executr app3.scss
else empty
Anyone an idea?
Use a namespace and apply it as a class to the root element. Wrap SASS statements in the appropriate namespaces. You can separate them into different files (partials) and combine them when they get compiled.
// in file _app1.scss
.app1 {
// rules you want applied in the "app1" case
}
// in file _app2.scss
.app2 {
// rules you want applied in the "app2" case
}
...
If you separate files into _app1.scss, _app2.scss, etc. then base.scss will include:
#import 'app1';
#import 'app2';
...
This combines the partial files into one when you compile. (You don't have to separate them, but it might be cleaner to do so.) Then, you do something like <body class="app1">... to use the app1 namespace, and only rules from _app1.scss will apply.

Material design lite inputs in Ember.js app loses it design after route transition

I am trying to use Material design lite with an Ember.js application and got the form working somehow. However, when the user navigates from one page to another page containing the form or inputs, the inputs do not seem to behave as expected. For an example here, when the page loads first time to home page, input works fine but when we switch between sign-in and home pages, inputs fallbacks to basic form and material design animation is lost.
Not sure if this issue is related to Ember.js or Material design but any help would be highly appreciated.
MDL requires elements to be initialized to get special effects such as buttons with ripples, or animated input boxes. They are initialized by default on page load, but elements inserted by views or components will not be initialized. The simplest approach is to initialize them on didInsertElement.
A more general approach would be a mixin which handles this for you, as in:
// mixins/mdl-button.js
export default Ember.Mixin.create() {
initializeMdlButtons: function() {
var buttons = this.get('element').querySelectorAll('.mdl-button');
[].forEach.call(buttons, button => componentHandler.upgradeElement(button));
}.on('didInsertElement')
Then in your component using buttons
import MdlButton from 'app/mixins/mdl-button';
export default Ember.Component.extend(MdlButton, {
...
});
Or, you could apply this to all components with
Ember.Component.reopen(MdlButton);
You will need to create handlers to initialize the required JS for each MDL component. You have two possibilities:
Use the JavaScript that comes with MDL, though it will become toublesome on some of the components.
Implement JS on your own per component, and use ideas of the JS internally in MDL.
I used 2. This is why I have written a ember-addon specifically to create ember components out of MDL.
It's pretty simple.
ember install ember-mdl
Demo / docs: http://peec.github.io/ember-mdl/
Example of implementation is in the dummy app
Or you can just do componentHandler.upgradeDom() on didInsertElement. Which based on their documentation
Searches existing DOM for elements of our component type and upgrades
them * if they have not already been upgraded.
initializeItems: function () {
componentHandler.upgradeDom();
}.on('didInsertElement')
Thanks #torazaburo for your suggestation. I had to modify mixin to get it working. In my case i have textfield input and needed to modify the mixing. Here is my solution if someone still needs.
// app/mixins/textfield-support.js
import Ember from 'ember';
export default Ember.Mixin.create({
initializeMdlTextfield: function() {
componentHandler.upgradeElement(this.get('element'), 'MaterialTextfield');
}.on('didInsertElement')
});
Then we can extend the mixing in our component as below.
// app/components/mdl-textfield-input.js
import Ember from 'ember';
import layout from '../templates/components/mdl-textfield-input';
import mdlTextfield from '../mixins/textfield-support';
export default Ember.Component.extend(mdlTextfield, {
tagName : 'div',
attributeBindings : ['disabled', 'type', 'name' ],
hasFloatingLabel : false,
containerClassNames : '',
labelText : null,
classNames : ['mdl-textfield', 'mdl-js-textfield'],
classNameBindings: [
'hasFloatingLabel:mdl-textfield--floating-label',
'containerClassNames'
],
layout
});
Component template would look something like this.
// app/templates/components/mdl-textfield-input.hbs
{{yield}}
{{input id=name value=value type=type disabled=disable classNames="mdl-textfield__input"}}
<label class="mdl-textfield__label" for={{name}}>{{labelText}}</label>
<span class="mdl-textfield__error">{{error}}</span>
And use this component as below.
{{mdl-textfield-input
name='username'
value=model.username
labelText='Username'
hasFloatingLabel=true
type='text'
containerClassNames ='mdl-cell--12-col'
}}

Is it possible to use Polymer inside of React?

I have been using React and look to use Polymer tags inside of React. React does not recognize Polymer tags as React only handles basic DOM tags. Is there a way to add the Polymer tags to React DOM library?
Yes, it is possible.
Create a polymer element.
<link rel="import" href="../../bower_components/polymer/polymer.html">
Polymer({
is: 'calender-element',
ready: function(){
this.textContent = "I am a calender";
}
});
Make the polymer component a html tag by importing it in a html page. E.g. import it in the index.html of your react application.
<link rel="import" href="./src/polymer-components/calender-element.html">
Use that element in the jsx file.
'use strict';
import React from 'react';
class MyComponent extends React.Component{
render(){
return (
<calender-element></calender-element>
);
}
}
export default MyComponent;
Is it possible to use Polymer inside of React?
Short answer: not really.
Long answer: kinda. You have to create components which directly create the nodes and manipulate attributes. There are also other considerations for children of the element, etc.
Is it possible to use React inside of Polymer?
It's pretty much the same answer this way, you'd have to wrap a React component in a polymer element.
Why?
Polymer (based on web components), and React (a ui component library), are both based on 'components'. Because there's no single way to express a component in web, you'll need to bridge between the various libraries. The same holds true for questions about 'react in angular', 'jquery plugin in react', 'knockout in jquery plugin', 'react in backbone', 'angular with polymer elements which use backbone and react with polymer elements which use angular', etc.
In a case like angular with polymer, you might think it's very simple, but polymer doesn't know about evaluating angular expressions, or any kind of declarative callbacks. You need a bridge in nearly every case, and they're never pretty.
this is a fairly old question but how about https://www.npmjs.com/package/react-polymer ? isn't this a support of polymer components for react?
import reactPolymer from 'react-polymer'; //IMPORTANT: Must be imported before React.
import React from 'react';
reactPolymer.registerAttribute('raised');
reactPolymer.registerAttribute('url');
reactPolymer.registerEvent('response', 'onResponse');
<paper-button raised>another button</paper-button>
<iron-ajax url="http://example.com/" onResponse={this.handleResponse} />
Answer according to current stages of react and polymer
Since this question was asked a while ago and a lot has changed since then, I'd like to add that you can now use polymer elements in react directly but for your custom attributes and events it causes problem it can easily be handle by using react-polymer, It has support for almost all elements, with exception of gold-* elements.
Why would you want to use Polymer with react?
It can further simplify your development process or make it a big mess. It depends on how you use it
Speed of development and ease of use offered by polymer components is unrivaled.
React can further break down your components comprising of polymer components, into manageable pieces.
Simply because, react and JSX is love.
Hey why the hell not??
The answer is YES. But it is not straight forward. So, I tried following some documentations which are around in fact even the official one but the best was this: https://medium.com/jens-jansson/start-using-web-components-in-react-6ccca2ca21f9
I followed the steps mentioned and it worked! I am also mentioning the github repo wherein I tried to integrate the vaadin datepicker and also one of the polymer element paper-input. https://github.com/manit815/react-with-webcomponent
Yes, you can use Polymer element inside react.
Create Polymer element
import { LitElement, html } from 'lit-element';
export class CustomButton extends LitElement {
static get properties() {
return {
isDisabled : { type: Boolean },
buttonType: { type: String },
};
}
constructor() {
super();
this.isDisabled = false;
this.button = 'button';
}
render() {
return html`
<button>
<slot></slot>
</button>
`;
}
}
customElements.define('polymer-button', CustomButton);
Import the element into an HTML file using <script type="module">.
Use the import statement (as shown above) to import it from another ES6 module.
<script type="module" src="./polymer-button.js">
Once you've imported it, you can use a custom element just like you'd use a standard element.
import React from 'react';
export const PolymerButton = () => {
return (
<polymer-button />
)
}
I just tried this today and I was able to successfully use the material elements from their element catalog. I haven't gotten around to testing it thoroughly, but as far as using the tags in React goes, it works and all the html and css is there.
To use existing elements, just follow their using elements guide.

Can I create links with 'target="_blank"' in Markdown?

Is there a way to create a link in Markdown that opens in a new window? If not, what syntax do you recommend to do this? I'll add it to the markdown compiler I use. I think it should be an option.
As far as the Markdown syntax is concerned, if you want to get that detailed, you'll just have to use HTML.
Hello, world!
Most Markdown engines I've seen allow plain old HTML, just for situations like this where a generic text markup system just won't cut it. (The StackOverflow engine, for example.) They then run the entire output through an HTML whitelist filter, regardless, since even a Markdown-only document can easily contain XSS attacks. As such, if you or your users want to create _blank links, then they probably still can.
If that's a feature you're going to be using often, it might make sense to create your own syntax, but it's generally not a vital feature. If I want to launch that link in a new window, I'll ctrl-click it myself, thanks.
Kramdown supports it. It's compatible with standard Markdown syntax, but has many extensions, too. You would use it like this:
[link](url){:target="_blank"}
I don't think there is a markdown feature, although there may be other options available if you want to open links which point outside your own site automatically with JavaScript.
Array.from(javascript.links)
.filter(link => link.hostname != window.location.hostname)
.forEach(link => link.target = '_blank');
jsFiddle.
If you're using jQuery:
$(document.links).filter(function() {
return this.hostname != window.location.hostname;
}).attr('target', '_blank');
jsFiddle.
With Markdown v2.5.2, you can use this:
[link](URL){:target="_blank"}
So, it isn't quite true that you cannot add link attributes to a Markdown URL. To add attributes, check with the underlying markdown parser being used and what their extensions are.
In particular, pandoc has an extension to enable link_attributes, which allow markup in the link. e.g.
[Hello, world!](http://example.com/){target="_blank"}
For those coming from R (e.g. using rmarkdown, bookdown, blogdown and so on), this is the syntax you want.
For those not using R, you may need to enable the extension in the call to pandoc with +link_attributes
Note: This is different than the kramdown parser's support, which is one the accepted answers above. In particular, note that kramdown differs from pandoc since it requires a colon -- : -- at the start of the curly brackets -- {}, e.g.
[link](http://example.com){:hreflang="de"}
In particular:
# Pandoc
{ attribute1="value1" attribute2="value2"}
# Kramdown
{: attribute1="value1" attribute2="value2"}
^
^ Colon
One global solution is to put <base target="_blank">
into your page's <head> element. That effectively adds a default target to every anchor element. I use markdown to create content on my Wordpress-based web site, and my theme customizer will let me inject that code into the top of every page. If your theme doesn't do that, there's a plug-in
Not a direct answer, but may help some people ending up here.
If you are using GatsbyJS there is a plugin that automatically adds target="_blank" to external links in your markdown.
It's called gatsby-remark-external-links and is used like so:
yarn add gatsby-remark-external-links
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [{
resolve: "gatsby-remark-external-links",
options: {
target: "_blank",
rel: "noopener noreferrer"
}
}]
}
},
It also takes care of the rel="noopener noreferrer".
Reference the docs if you need more options.
For ghost markdown use:
[Google](https://google.com" target="_blank)
Found it here:
https://cmatskas.com/open-external-links-in-a-new-window-ghost/
I'm using Grav CMS and this works perfectly:
Body/Content:
Some text[1]
Body/Reference:
[1]: http://somelink.com/?target=_blank
Just make sure that the target attribute is passed first, if there are additional attributes in the link, copy/paste them to the end of the reference URL.
Also work as direct link:
[Go to this page](http://somelink.com/?target=_blank)
You can do this via native javascript code like so:
var pattern = /a href=/g;
var sanitizedMarkDownText = rawMarkDownText.replace(pattern,"a target='_blank' href=");
JSFiddle Code
In my project I'm doing this and it works fine:
[Link](https://example.org/ "title" target="_blank")
Link
But not all parsers let you do that.
There's no easy way to do it, and like #alex has noted you'll need to use JavaScript. His answer is the best solution but in order to optimize it, you might want to filter only to the post-content links.
<script>
var links = document.querySelectorAll( '.post-content a' );
for (var i = 0, length = links.length; i < length; i++) {
if (links[i].hostname != window.location.hostname) {
links[i].target = '_blank';
}
}
</script>
The code is compatible with IE8+ and you can add it to the bottom of your page. Note that you'll need to change the ".post-content a" to the class that you're using for your posts.
As seen here: http://blog.hubii.com/target-_blank-for-links-on-ghost/
If someone is looking for a global rmarkdown (pandoc) solution.
Using Pandoc Lua Filter
You could write your own Pandoc Lua Filter which adds target="_blank" to all links:
Write a Pandoc Lua Filter, name it for example links.lua
function Link(element)
if
string.sub(element.target, 1, 1) ~= "#"
then
element.attributes.target = "_blank"
end
return element
end
Then update your _output.yml
bookdown::gitbook:
pandoc_args:
- --lua-filter=links.lua
Inject <base target="_blank"> in Header
An alternative solution would be to inject <base target="_blank"> in the HTML head section using the includes option:
Create a new HTML file, name it for example links.html
<base target="_blank">
Then update your _output.yml
bookdown::gitbook:
includes:
in_header: links.html
Note: This solution may also open new tabs for hash (#) pointers/URLs. I have not tested this solution with such URLs.
In Laravel I solved it this way:
$post->text= Str::replace('<a ', '<a target="_blank"', $post->text);
Not works for a specific link. Edit all links in the Markdown text. (In my case it's fine)
I ran into this problem when trying to implement markdown using PHP.
Since the user generated links created with markdown need to open in a new tab but site links need to stay in tab I changed markdown to only generate links that open in a new tab. So not all links on the page link out, just the ones that use markdown.
In markdown I changed all the link output to be <a target='_blank' href="..."> which was easy enough using find/replace.
I do not agree that it's a better user experience to stay within one browser tab. If you want people to stay on your site, or come back to finish reading that article, send them off in a new tab.
Building on #davidmorrow's answer, throw this javascript into your site and turn just external links into links with target=_blank:
<script type="text/javascript" charset="utf-8">
// Creating custom :external selector
$.expr[':'].external = function(obj){
return !obj.href.match(/^mailto\:/)
&& (obj.hostname != location.hostname);
};
$(function(){
// Add 'external' CSS class to all external links
$('a:external').addClass('external');
// turn target into target=_blank for elements w external class
$(".external").attr('target','_blank');
})
</script>
You can add any attributes using {[attr]="[prop]"}
For example [Google] (http://www.google.com){target="_blank"}
For completed alex answered (Dec 13 '10)
A more smart injection target could be done with this code :
/*
* For all links in the current page...
*/
$(document.links).filter(function() {
/*
* ...keep them without `target` already setted...
*/
return !this.target;
}).filter(function() {
/*
* ...and keep them are not on current domain...
*/
return this.hostname !== window.location.hostname ||
/*
* ...or are not a web file (.pdf, .jpg, .png, .js, .mp4, etc.).
*/
/\.(?!html?|php3?|aspx?)([a-z]{0,3}|[a-zt]{0,4})$/.test(this.pathname);
/*
* For all link kept, add the `target="_blank"` attribute.
*/
}).attr('target', '_blank');
You could change the regexp exceptions with adding more extension in (?!html?|php3?|aspx?) group construct (understand this regexp here: https://regex101.com/r/sE6gT9/3).
and for a without jQuery version, check code below:
var links = document.links;
for (var i = 0; i < links.length; i++) {
if (!links[i].target) {
if (
links[i].hostname !== window.location.hostname ||
/\.(?!html?)([a-z]{0,3}|[a-zt]{0,4})$/.test(links[i].pathname)
) {
links[i].target = '_blank';
}
}
}
Automated for external links only, using GNU sed & make
If one would like to do this systematically for all external links, CSS is no option. However, one could run the following sed command once the (X)HTML has been created from Markdown:
sed -i 's|href="http|target="_blank" href="http|g' index.html
This can be further automated by adding above sed command to a makefile. For details, see GNU make or see how I have done that on my website.
If you just want to do this in a specific link, just use the inline attribute list syntax as others have answered, or just use HTML.
If you want to do this in all generated <a> tags, depends on your Markdown compiler, maybe you need an extension of it.
I am doing this for my blog these days, which is generated by pelican, which use Python-Markdown. And I found an extension for Python-Markdown Phuker/markdown_link_attr_modifier, it works well. Note that an old extension called newtab seems not work in Python-Markdown 3.x.
For React + Markdown environment:
I created a reusable component:
export type TargetBlankLinkProps = {
label?: string;
href?: string;
};
export const TargetBlankLink = ({
label = "",
href = "",
}: TargetBlankLinkProps) => (
<a href={href} target="__blank">
{label}
</a>
);
And I use it wherever I need a link that open in a new window.
For "markdown-to-jsx" with MUI v5
This seem to work for me:
import Markdown from 'markdown-to-jsx';
...
const MarkdownLink = ({ children, ...props }) => (
<Link {...props}>{children}</Link>
);
...
<Markdown
options={{
forceBlock: true,
overrides: {
a: {
component: MarkdownLink,
props: {
target: '_blank',
},
},
},
}}
>
{description}
</Markdown>
This works for me: [Page Link](your url here "(target|_blank)")