Inject varables in css, html, js with Webpack - javascript

I have problem, that in my project I use constants, variables in css, html, js and if I wanna something change some constants I need find it in html or css or js, that take long time. And wonder if it possible have separate js file with variables and constants, and inject value from that to html, js, css (sass). Pseudocode below. I wanna know, is even possible do with webpack, if yes, how or where I should look?
document.getElementById(${=name}).style.color = 'white';
.box {
width: ${=width}
}
<div class="box box_${=id}">
Some text
</div>
const css = {
width: '250px',
};
const html = {
id: '2'
};
const js = {
id: 'haha',
};

You can use a webpack plugin for doing all replacement.
for instance:
https://github.com/jamesandersen/string-replace-webpack-plugin
It can replace in any files you want...
for JS (for instance) you would have something like:
module: {
loaders: [
// configure replacements for file patterns
{
test: /.js$/,
loader: StringReplacePlugin.replace({
replacements: [
{
pattern: /DEFAULT_WIDTH/ig,
replacement: function () {
return '100px';
}
}
]})
}
]
},

Related

Inline Js with Vue-Meta In Nuxt.js

Basically, Im using Nuxt 2.9.2, and trying to using innerHTML method to inline a Google Optimize script, but whenever i run npm run generate, the code transforms certain aspects even though __dangerouslyDisableSanitizers is whitelisting innerHTML..
This is my Script in Nuxt Config head object
script: [
{
innerHTML: `(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};(a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;})(window,document.documentElement,'async-hide','dataLayer', 500 , ${JSON.stringify(
{ [process.env.GOOGLE_OPTIMIZE_ID]: true }
)})`
}
],
__dangerouslyDisableSanitizers: ['innerHTML']
},
Which renders out as the below, tried multiple different ways. could not get it to inline as expected
!function(e,n,t,a,c,s,d){n.className+=" "+t,s.start=1*new Date,s.end=d=function(){n.className=n.className.replace(RegExp(" ?"+t),"")},(e[a]=e[a]||[]).hide=s,setTimeout(function(){d(),s.end=null},500),s.timeout=500}(window,document.documentElement,"async-hide","dataLayer",0,{"GTM-XXXXXX":!0})
should be
(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};(a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;})(window,document.documentElement,'async-hide','dataLayer', 500 , 'GTM-XXXXXX'': true }
)})
script: [
{
innerHTML: `window.MY_CONST = 'abcd1234'`,
type: 'text/javascript',
charset: 'utf-8',
},
],
__dangerouslyDisableSanitizers: ['script', 'innerHTML'],

Is it possible to pass a Sass variable to Laravel/Blade/JS?

I'm trying to get a variable I use in Sass over to Laravel/Blade/JS so that I can use one variable defined in one place to maintain something across the various languages used to maintain the site.
Is it possible to pass a Sass variable to Laravel/Blade/JS so I can do this? Thanks.
If using Webpack, you can do this easily with :export without the need for additional dependencies.
webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
}]
}
};
variables.scss
$white-color: #fcf5ed;
$dark-color: #402f2b;
$light-color: #e6d5c3;
$medium-color: #977978;
$alert-color: #cb492a;
$light-black-color: #706e72;
$black-color: #414042;
// the :export directive is the magic sauce for webpack
:export {
whitecolor: $white-color;
darkcolor: $dark-color;
lightcolor: $light-color;
mediumcolor: $medium-color;
alertcolor: $alert-color;
lightblackcolor: $light-black-color;
blackcolor: $black-color;
}
file.js
import variables from 'variables.scss';
const CSS = {
backgroundColor: variables.blackcolor
}
export default ({}) => {
return <div style={CSS}>Content</div>
}
You can use this library to pass Sass variables to JS.
https://www.npmjs.com/package/sass-to-js
here's an example,
SASS:
$colorMap: (
colorHexShort: #f00,
colorHex: #ff0000,
colorRgba: rgba(255, 0, 0, 0.5),
blackGradations: ('#000', '#111', '#222')
);
.colors-data{
&:before{
content: sassToJs($colorMap);
display: none;
}
}
JS:
var colorsDataEl = $('.colors-data');
var colorsData = colorsDataEl.sassToJs({pseudoEl:":before", cssProperty: "content"});
colorsDataEl.html(JSON.stringify(colorsData));
Here a kind of custom solution to export your Sass variables to a Js file.
First my Sass variables :
$bifurcation : violet;
$simple : green;
$multiple : orange;
$crossing : yellow;
$common : brown;
I put them into an unknown css property :
variable_to_export {
start_export: unset;
bifurcation: $bifurcation;
simple: $simple;
multiple: $multiple;
crossing: $crossing;
common: $common;
end_export: unset;
}
On my js file, i'm going to read the compiled scss file containing my 'variable_to_export'. This block of code is in a function that I can export to all my files that need it :
export function variables() {
var variables = [];
$.ajax({
url: "/css/global.css",
dataType: "text",
success: function(css) {
var position = css.indexOf('start_export');
var position_end = css.indexOf('end_export');
var clean = css.slice(position, position_end).replace(/ /g, '').replaceAll(';', '');
var array_variables = clean.split(/\r?\n/);
array_variables.forEach(function(element) {
var split = element.split(':');
if (split[0] != 'start_export' && split[0] != '') {
variables[split[0]] = split[1];
}
});
}
});
return variables;
}
At this stage we have an array containing the name of the css property as index, and the value of the Sass variable in my desired js files.
Result here
I think there are surely things to improve, the solution is a bit rooty but it works.

How to properly write a vuepress plugin?

I am trying to write a Vuepress plugin to make use of App Level enhancement and install a Vue plugin. But I can't seem to get this to work. Can you please take a look at the code below and see what is wrong?
{.vuepress/config.js}
module.exports = {
plugins: [
require('./builder.plugin.js')
]
}
{.vuepress/builder.plugin.js}
module.exports = (option, ctx) => {
return {
enhanceAppFiles: [{
name: 'builder-plugin',
content: `export default ({ Vue }) => {
Vue.component('b-header', {
name: 'b-header',
template: '<div id="header"><slot /></div>'
})
}`
}]
}
}
{README.md}
# Introduction
<b-header>Test from component</b-header>
The final error I get is:
Unknown custom element: <b-header> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I actually found the answer. The above did not work because I was mixing client site code with runtime code by using a plugin.
The trick was to use enhanceAPP hook.
ref: https://vuepress.vuejs.org/guide/basic-config.html#theme-configuration

Vue 2 component styles without Vue loader

Considering that there is single file component (as shown in the guide),
<style>
.example {
color: red;
}
</style>
<template>
<div class="example">hi</div>
</template>
How can the same thing be done without Vue loader in non-modular ES5/ES6 environment?
Considering that the style is scoped,
<style scoped>
.example {
color: red;
}
</style>
Is there a way to implement scoped CSS in non-modular environment, too? If there's none, is there a way to implement it in modular environment (Webpack), but without Vue loader and custom .vue format?
Instead of using the template instance in the Vue component, you can harness a 'closer-to-the-compiler alternative' with the render function without the need for the Vue Loader or compiler. You can add any additional attributes with the second parameter in the createElement function and this will give you a lot of flexibility on top of just styles.
See the Render Functions section in the guide for more info and the full options allowed in the data obj:
https://v2.vuejs.org/v2/guide/render-function
https://v2.vuejs.org/v2/guide/render-function#The-Data-Object-In-Depth
Note: The caveat here is that the style will only apply to the component it is declared in, so it might not be able to used across multiple components of the same class like CSS would be. Not sure if thats also what you want to achieve.
An example from the docs catered to this use case:
Vue.component('example', {
// render function as alternative to 'template'
render: function (createElement) {
return createElement(
// {String | Object | Function}
// An HTML tag name, component options, or function
// returning one of these. Required.
'h2',
// {Object}
// A data object corresponding to the attributes
// you would use in a template. Optional.
{
style: {
color: 'red',
fontSize: '28px',
},
domProps: {
innerHTML: 'My Example Header'
}
},
// {String | Array}
// Children VNodes. Optional.
[]
)}
});
var example = new Vue({
el: '#yourExampleId'
});
It can be achieved putting the scope manually, as vue-loader does automatically.
This is the example of the documentation. Adding some kind of ID, "_v-f3f3eg9" in this case, to scope the class only for that element.
<style>
.example[_v-f3f3eg9] {
color: red;
}
</style>
Vue.component('my-component', {
template: '<div class="example" _v-f3f3eg9>hi</div>'
});
I use Rollup (+ Bublé) + Vue.js all the time. It's pretty simple and fast.
The Rollup config is like:
import vue from 'rollup-plugin-vue';
import resolve from 'rollup-plugin-node-resolve';
import buble from 'rollup-plugin-buble';
const pkg = require('./package.json');
const external = Object.keys(pkg.dependencies);
export default {
external,
globals: { vue: 'Vue' },
entry: 'src/entry.js',
plugins: [
resolve(),
vue({ compileTemplate: true, css: true }),
buble({ target: { ie: 9 }})
],
targets: [
{ dest: 'dist/vue-rollup-example.cjs.js', format: 'cjs' },
{ dest: 'dist/vue-rollup-example.umd.js', format: 'umd' }
]
};
I've made a boilerplate repo:
git clone https://github.com/jonataswalker/vue-rollup-example.git
cd vue-rollup-example
npm install
npm run build

generating templates with grunt - looking for a task

I've got an HTML file with following content:
<html>
<body>
<span>{{ secret }}</span>
</body>
</html>
I'm looking for a grunt task that could take this source file, take a map of values:
grunt.initConfig({
myTask: {
myTarget: {
src: ...
dest: ...
values: {
secret: 'ABC'
}
}
}
})
and generate output file:
<html>
<body>
<span>ABC</span>
</body>
</html>
Is there any task like this? I saw grunt-mustache-html but it forces lots of things to exist which I really don't need and I don't want to use it. I want simply to take a single mustache (or hbs or whatever), fill it with data from grunt-level object and dump the result into another HTML file, that's all.
You could try grunt-template which processed lo-dash templates. Here's a basic setup to solve your problem:
//Gruntfile.js
config.template = {
myTask: {
options: {
data: function () {
return {
secret: 'ABC'
};
}
},
files: {
'output.html: ['template.html.tpl']
}
}
};
//template.html.tpl
<html>
<body>
<span><%= secret %></span>
</body>
</html>
#1. One options is to make use of grunt.template utility (see lagerone's answer). With custom delimiters you can achieve pretty close result to what you want:
grunt.template.addDelimiters('myDelimiters', '{{', '}}');
In this case your template will have to use {{= secret }} tags.
#2. Another option is that you can always write you own simple task. In your case it can look like this:
grunt.initConfig({
myTask: {
options: {
data: {
secret: 'ABC'
},
src: 'index.html',
dest: 'index.output.html'
}
}
});
grunt.registerTask('myTask', function() {
var options = this.options(),
template = grunt.file.read(options.src);
var content = template.replace(/\{\{\s*(.*?)\s*\}\}/g, function(a, b) {
return typeof options.data[b] !== undefined ? options.data[b] : '';
});
grunt.file.write(options.dest, content);
});
grunt.registerTask('default', ['myTask']);
I have used grunt-include-replace in the past. Is easy to use. In your gruntfile you will create a task similar to this one (Example taken from official github repo):
grunt.initConfig({
includereplace: {
your_target: {
options: {
// Task-specific options go here.
},
// Files to perform replacements and includes with
src: '*.html',
// Destination directory to copy files to
dest: 'dist/'
}
}
})

Categories

Resources