Problem I'm trying to solve:
I want to have one file with exports, info.js, that are variables including markup or pure strings.
For example;
export const title = "Some title"
export const mainText = (<b> I'm so texty </b>, mark me up like I'm a hot reloadable)
In JSX world, mainText is fine, in Svelte world, mainText needs to be a string which I then load with the #html thingy {#html mainText}.
Semi solution with issue I'd like input on:
Although, when I load with #html, the styles within the .svelte file are not applied. Fine, I can do that with :global, but... my second issue is that markup in a string is annoying too - can't prettify it.
What should I be doing?
Create a separate file for html-like syntax, markup in a string won't be very pretty, not much to do about it. You can load and parse .html from the back-end or something, but it's not the best thing as well.
Styles should be global, because it's not intended to work in this way (scoping out of box), but you can have your separate styles file as well in the static folder or send from the back-end with html as a separate and independent page.
Generally, I'd advise to refactor everything, so you can use Svelte as it's supposed to be used.
Related
There is something I find very confusing when working in React.js.
There are plenty of examples available on internet which use .js files with React but many others use .jsx files.
I have read about JSX files and my understanding is that they just let you write HTML tags within your JavaScript.
But the same thing can be written in JS files as well.
So what is the actual difference between .js and .jsx ?
There is none when it comes to file extensions. Your bundler/transpiler/whatever takes care of resolving what type of file contents there is.
There are however some other considerations when deciding what to put into a .js or a .jsx file type. Since JSX isn't standard JavaScript one could argue that anything that is not "plain" JavaScript should go into its own extensions ie., .jsx for JSX and .ts for TypeScript for example.
There's a good discussion here available for read
In most of the cases it’s only a need for the transpiler/bundler, which might not be configured to work with JSX files, but with JS! So you are forced to use JS files instead of JSX.
And since react is just a library for javascript, it makes no difference for you to choose between JSX or JS. They’re completely interchangeable!
In some cases users/developers might also choose JSX over JS, because of code highlighting, but the most of the newer editors are also viewing the react syntax correctly in JS files.
JSX tags (<Component/>) are clearly not standard javascript and have no special meaning if you put them inside a naked <script> tag for example. Hence all React files that contain them are JSX and not JS.
By convention, the entry point of a React application is usually .js instead of .jsx even though it contains React components. It could as well be .jsx. Any other JSX files usually have the .jsx extension.
In any case, the reason there is ambiguity is because ultimately the extension does not matter much since the transpiler happily munches any kinds of files as long as they are actually JSX.
My advice would be: don't worry about it.
As other mentioned JSX is not a standard Javascript extension. It's better to name your entry point of Application based on .js and for the rest components, you can use .jsx.
I have an important reason for why I'm using .JSX for all component's file names.
Actually, In a large scale project with huge bunch of code, if we set all React's component with .jsx extension, It'll be easier while navigating to different javascript files across the project(like helpers, middleware, etc.) and you know this is a React Component and not other types of the javascript file.
As already mentioned, there is no difference, if you create a file with .jsx or .js.
I would like to bring another expect of creating the files as .jsx while creating a component.
This is not mandatory, but an architectural approach that we can follow. So, in large projects we divide our components as Presentational components or Container components. Just to brief, in container components we write the logic to get data for the component and render the Presentational component with props. In presentational components, we usually donot write functional logic, presentational components are used to represent the UI with required props.
So, if you check the definition on JSX in React documents.
It says,
const element = <h1>Hello, world!</h1>;
It is called JSX, and it is a syntax extension to JavaScript. We
recommend using it with React to describe what the UI should look
like. JSX may remind you of a template language, but it comes with
the full power of JavaScript.
JSX produces React “elements”. Instead of artificially separating
technologies by putting markup and logic in separate files, React
separates concerns with loosely coupled units called “components”
that contain both.
React doesn’t require using JSX, but most people find it helpful as a
visual aid when working with UI inside the JavaScript code. It also
allows React to show more useful error and warning messages.
It means, It's not mandatory but you can think of creating presentational components with '.jsx' as it actually binds the props with the UI. and container components, as .js files as those contains logic to get the data.
It's a convention that you can follow while creating the .jsx or .js files, to logically and physically separate the code.
Besides the mentioned fact that JSX tags are not standard javascript, the reason I use .jsx extension is because with it Emmet still works in the editor - you know, that useful plugin that expands html code, for example ul>li into
<ul>
<li></li>
</ul>
JSX isn't standard JavaScript, based to Airbnb style guide 'eslint' could consider this pattern
// filename: MyComponent.js
function MyComponent() {
return <div />;
}
as a warning, if you named your file MyComponent.jsx it will pass , unless if you edit the eslint rule
you can check the style guide here
Depending on the IDE or editor, .jsx has a different file icon :P. And it's a good practice to know what file it is without reading the code. The bundler and compiler might know it and will take care of everything, but telling the difference between .jsx and .js from just the file name will help you as a developer a lot.
EDIT: jsx is more than js, it is javascript + xml, which allows you to write html inside a js file without using template strings. For this reason it's a good practice to use .jsxfor your react files, instead of .js (which is also valid).
if you use .jsx it will be treated as a react page so its features will be applied by extensions automatically. for example if you use emmet in .jsx file, .container, this will create a div with className not class
<div className="container"></div>
if you apply the same emmet inside a js file, you would get this:
<div class="container"></div>
copied from: https://reactjs.org/docs/introducing-jsx.html
Why JSX? React embraces the fact that rendering logic is inherently coupled with other UI logic: how events are handled, how
the state changes over time, and how the data is prepared for display.
Instead of artificially separating technologies by putting markup and
logic in separate files, React separates concerns with loosely coupled
units called “components” that contain both. We will come back to
components in a further section, but if you’re not yet comfortable
putting markup in JS, this talk might convince you otherwise.
React doesn’t require using JSX, but most people find it helpful as a
visual aid when working with UI inside the JavaScript code. It also
allows React to show more useful error and warning messages.
HTML templates are nice and fast. The problem is HTML import has been deprecated. This means it makes the most sense to put web components each in their own .js file instead of .html files. However if one uses a .js file, then as far as I can tell, one can't use a precompiled template to attach at the shadow DOM, one has to use some fixed string that I imagine is parsed every time.
With .html web component one could do:
shadowRoot.appendChild(myTemplate.content.cloneNode(true));
However in a .js file you have to do something like:
something.innerHTML = `
<style>
...
/* lots of style */
</style>
<b>I'm in shadow dom!</b>
<!-- lots of html -->
<slot></slot>
`;
Is this not a bad idea because the text must be revaulated every time, whereas a template is evaulated once?
So what is the recommened way of embedding one's style and html in a .js file for a web component?
I am using vanilla JS, no frameworks.
+1 for Vanilla code, your code will last another 26 JavaScript years.
There is no recommended way, it all depends on your use case.
You can put <template id="MY-COMPONENT">in your main HTML file,
and do document.getElementById("MY-COMPONENT").content.cloneNode(true) in your component code (knowing when your DOM is ready)
You can do document.createElement("template"), and take it from there
You can use the <load-file> Web Component to load external HTML files.
(no template advantage here)
So it all comes down to understanding what your application needs.
Note that the pattern you see in many blogs:
let template = document.createElement("template");
template.innerHTML = ` CSS & HTML CONTENT `;
...
this.shadowRoot.appendChild(template..content.cloneNode(true));
In many use cases, where a parsed template is hardly re- used, is an expensive way of writing:
this.shadowRoot.innerHTML = ` CSS & HTML CONTENT `;
Be aware the append template approach has (potential) (edge-case) disadvantages as well;
its content is parsed async, while .innerHTML= is synchronous.
An while you are at it, be sure to learn the differences:
https://developer.mozilla.org/en-US/docs/Web/API/Element/append (no IE support)
https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild
Long story short I have strings that contain HTML which are downloaded before a production build from a secure server. The framework we're using is React with Gatsby and typically you would just do the following:
<div dangerouslySetInnerHTML={{__html: '<p>My Stuff</p>'}}></div>
Which works fine, the main problem is for SEO purposes we want the html to be compiled into html rather than being rendered with Javascript.
Seeing as it's already HTML is there a way I can disable the protection inside react so these strings aren't escaped by default and become regular HTML in the production build?
Not practically, no. It's important to distinguish a <div> in a .jsx file from a <div> in html. If you look at the compiled output of the jsx, it will reveal what's really going on. If you transpile a react component containing <div>Hello world</div>, you'll get a function call along the lines of _react.createElement("div", null, "Hello world"). Anything that is put into the body of the div will also be inserted into it as JSX elements. The dangerouslySetInnerHtml prop is there to tell React that the value is actual html that you trust. However, even if there were an option other than dangerouslySetInnerHtml, I don't believe it would solve your problem as anything inside your react is going to have to wait for client side rendering.
Now, I'm no SEO expert, but if it's crucial to have content on the page before you render it, you may be able to send in the original html in a hidden element. If your original markup has <div id="app">Some seo stuff</div>, React will replace the content of the div when it renders it.
I think what you need is SSR; React allows this feature
You could install a server adapter (maybe expressjs) and use it to render a first screen (which is most likely SEO related) and once the client side is ready to render, it would hydrate the pages. Since you have the HTML gotten from a server, I think this is best route to go
var stringToHTML = function(htmlContent) {
var dom = document.getElementById('integrationMessage');
dom.innerHTML = htmlContent;
return dom;
};
stringToHTML(res.data.message);
<div id = "integrationMessage"></div>
I'm learning React: totally newbie.
If I save in DB the HTML directly from draft.js (or it's variants always based on it) and then in a view page of my React SPA I retrieve HTML from DB through my API:
QUESTIONS:
how can I render that HTML?
dangerouslySetInnerHTML? Or maybe one of this (what do you suggest?)?
https://github.com/wrakky/react-html-parser
https://github.com/pveyes/htmr
https://github.com/remarkablemark/html-react-parser
https://github.com/utatti/react-render-html
https://github.com/aknuds1/html-to-react
I read words like "sanitize", "securing HTML". But how, there is a library?
I need to secure html from draft-js when I save it in DB or after, when I'm rendering it?
Draft-JS doesn't allows you to directly generate HTML from the present EditorState and that's a good thing. Since you are not dealing with "Raw HTML" you don't have to deal with XSS attacks as Draft Editors internal state won't get altered if someone inserts a script in the Editor.
Draft JS allows you the export the current Editor state so that you can store it easily. It can be done using
import {convertToRaw} from 'draft-js';
and in your onChange Handler you can simply do
const editorJSON = JSON.stringify(convertToRaw(editorState.getCurrentContent()));
You can the store this JSON as you like for future use.
Now for Rendering this you have two options :
Generate HTML from the stored EditorState.
This can be done using Libraries like https://www.npmjs.com/package/draft-js-export-html. You might want to avoid this as the next option in my opinion is way better.
Use this EditorState as the Default value for a read only DraftJS Editor Component.
You are going to need convertFromRaw from DraftJS Library and then you make a Nice StateLess React Component like this
import React from 'react';
import {Editor, ConvertFromRaw} from 'draft-js';
const ReadOnlyEditor = (props) => {
const storedState = ConvertFromRaw(JSON.parse(props.storedState));
return (
<div className="readonly-editor">
<Editor editorState={storedState} readOnly={true} />
</div>
);
}
And Now you can simply use this to display your contents. You can also pass your decorators and custom mapping functions, typically everything you pass to the normal Editor and can render the content without loss of style and tedious dealing with HTML.
DO NOT Believe USERS!
The first thing you should care of is "Do NOT believe your USERS".
If your 'HTML' is rendered by your server and can't be modified by user, it's totally OK.
Because your rendered/saved HTML is totally safe and managed by yourself, and if it's assured as "SAFE" HTML, whether you put it(html) into DOM or not is not the problem at all.
But the problem is, most of WYSIWYG editors - like draft.js- makes "HTML" files not TEXT. I think your worry comes from here too.
Yes, It's dangerous. what we can do is NOT rendering HTML directly but "selective" HTML rendering.
Dangerous tags : <script>, <img>, <link>, etc.
you can remove those tags but it can be much safer when you decide which tags will you allow, like this:
Safe tags: <H1> - <H6> / span / div / p / ol ul li / table...
and you SHOULD remove those HTML element's attributes, like, onclick="", etc.
because it could be abused by users too.
Conclusion:
So what can we do when we use WYSIWYG editors?
There are 2 big strategies:
Generate "Safe" HTML when safe to Database.
Generate "Safe" HTML before putting it into DOM.
(3. Generate "Safe" HTML before sending html to client, but it is not in your case!)
Choose first one if you want to sure Database's text are totally safe.
First one must be processed in your server(not browser/client!), and you can use many solutions like BeautifulSoup in python, or sanitize-html in nodejs.
Choose second one if your web-app is complicated, and most of your service's business logic is running on front-end side.
Second one is using HTML escaping package just before mounting HTML into DOM. and still sanitize-html can be good solution. (surelly there's more great solutions!)
You can decide which tags/attribute/values in HTML.
Links
https://github.com/punkave/sanitize-html
in 2022 for me, it works a bit different way
import { convertFromRaw, Editor, EditorState } from 'draft-js';
function Comments() {
const itemText= EditorState.createWithContent(convertFromRaw(JSON.parse(item.content)));
return <Editor editorState={itemText} readOnly={true} />
}
and to the DB it was saved like that
JSON.stringify(convertToRaw(editorState.getCurrentContent()))
the difference is that for me without EditorState it doesn't work, I believe that I am not alone in that
I would like to ask your advice on our situation about dynamic/static loading components.
We're developing a "multi language teaching app" for Android/iOS. For UI text we use ng2-translate plugin (JSON files for each language). For the lesson content we use separate HTML files for each language. In the beginning the user selects a language to learn and then sees related lessons as a list (which comes from a JSON file too). Clicking a lesson loads the related HTML file and dynamically compiles directives/pipes in it (which makes it more interactive). By directives, I mean simple functions like showing a toast when user clicks a custom directive, like this: <example tooltip="explanation to show as a toast">An example sentence</example>. But maybe we can use more complex directives in the future.
Up to building the app, everything goes well in browser. But the AoT compiler does not support "dynamic loader components" in mobile devices, so we need to decide whether or not use this approach. And at that point I'm really confused. We may change our structure but I don't know which way is better.
As far as I can see, we have three options (if there are more, please enlighten me):
Stop using html files and convert each of them into a component with html templates (using AoT compiler (--prod mode)):
Be able to use directives/pipes
Gain interactivity
Gain performance (that's the main purpose of AoT, right? but what if I use hundreds of html pages/components? isn't it a bulky solution?)
Use hundreds of pre-compiled html pages for grammar lessons, stories, texts...
Load pure HTML files into an innerHTML of a loader component (using AoT compiler (--prod mode)):
Don't use directives/pipes
Loose interactivity (except being able to use simple HTML tags like p, strong, em, table etc. --if we count this as an interactive content)
Gain performance a bit (as we use AoT?)
Load HTML files dynamically as components via one dynamic template component (using JiT compiler (--dev mode)):
Be able to use directives/pipes
Use separate html files
Gain interactivity
Loose performance
Do something that Angular generally does not recommend
I can't decide what to do now, if I want more interactivity, I should drop the performance that Angular proposes.
I just wanted to be able to handle these grammar lessons in a simple syntax (like HTML) as seperate files and not to use/declare components for each of them...
What would you recommend?
I asked same question to Ionic forum and I decided to implement the solution of a user that replied to me:
I went through this with Markdown, tried a bunch of things, and here's what I eventually settled on:
Store your objects however is convenient for you. In my case, that's markdown source.
Define two components; we'll call them skeleton and bone for now.
skeleton has an input property giving it the source. In ngOnChanges, you need to parse that source into an array of elements, each corresponding to a different type of bone.
skeleton's template looks something like this:
<template ngFor let-bone [ngForOf]="bones">
<app-bone [bone]="bone"></app-bone>
</template>
Make sure each bone has a discriminator indicating its type, and then the BoneComponent template is a big giant switch:
<blockquote *ngIf="bone.tag === 'blockquote'">
<app-bone *ngFor="let child of bone.children" [bone]="child"></app-bone>
</blockquote>
<br *ngIf="bone.tag === 'br'">
... every other block-level element we support...
Note that this can work recursively if you need it to, in that the
inside of the blockquote case is effectively another skeleton. I'm
using HTML elements here, but the general technique works equally well
for other user-defined components (as types of bones).