Is it possible to import css file conditionally in Vue.js? - javascript

I have my admin-panel and pages for clients in one Vue.js project. Is it possible to use certain css-files only if the current route has "forAdmin" meta?

In your mounted() function you can add it like this.
if(someCondition) {
var element = document.createElement("link");
element.setAttribute("rel", "stylesheet");
element.setAttribute("type", "text/css");
element.setAttribute("href", "external.css");
document.getElementsByTagName("head")[0].appendChild(element);
}

By using style-loader with the useable API, you can dynamically apply and remove a stylesheet in your code.
First you'll need to update your webpack config rules so that stylesheets with the .useable.css extension will be loaded with the useable API:
{
test: /\.css$/,
exclude: /\.useable.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.useable\.css$/,
use: [
'style-loader/useable',
'css-loader'
]
}
Now in your router code file, you can import your stylesheet and .use() and .unuse() it according to your condition:
import style from './admin.useable.css'
const router = new VueRouter(...)
router.afterEach((to, from) => {
for (const route of to.matched) {
if (route.meta.forAdmin) {
style.use()
}
}
for (const route of from.matched) {
if (route.meta.forAdmin) {
style.unuse()
}
}
})
Make sure you balance the total number of .use() and .unuse() calls correctly because a reference count is maintained behind the scenes to figure out when the stylesheet should be applied.
I'm not sure what your setup is, so there might be a better way of doing what you want though.

Related

How to properly export an ES6 module function as a library for use in a node app?

Let's say that I have a node.js application, which does NOT go through my webpack bundling:
Node App
const Html = require('./build/ssr-bundle.js');
let result = Html.ssrbundle.render();
console.log(result);
Here is my ES6/JSX file, which is getting processed by webpack and I want to be able to access that render function in my node app (you guessed right, I am trying to SSR react stuff ;) )
src/Html.js -(webpack)-> build/ssr-bundle.js
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import CustomComponent from './custom-component.js';
module.exports = {
render : function () {
return ReactDOMServer.renderToString(<CustomComponent />);
} };
And here is my Webpack config
webpack.config.js
var path = require('path');
module.exports = {
entry: {
ssr: './src/Html.js',
//frontend: './src/frontend-Html.js'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: 'ssr-bundle.js',
library: 'ssrbundle'
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['env','react'],
plugins: ["transform-es2015-destructuring", "transform-object-rest-spread"]
}
},
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
},
stats: {
colors: true
},
devtool: 'source-map'
};
Whatever I do, I cannot figure out how to properly use that exported variable "ssrbundle" and subsequently the render function. If I had my node app included in the bundle, everything would be all right, but this is not what I want to do.
As apokryfos suggested, I played around with the libraryTarget Webpack setting. You can find more info on using Webpack to author a library (what I was really trying to achieve) here:
https://webpack.js.org/guides/author-libraries/
and here are code examples:
https://github.com/kalcifer/webpack-library-example/blob/master/webpack.config.babel.js.
What did the trick for me, was to set the libraryTarget to "umd" , which is different than the "var" setting which is set by default and is suitable i.e. for including the script in an HTML file

How can I pull out certain items from rxjs?

I'm writing a lib that has rxjs as a dependency. It only uses Subject - Is it possible for me to extract that one feature and include it within my lib, removing the need for rxjs as a dependency?
No. check inner dependencies Subject rely on (https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts#L1-L8). It is pretty much requiring most of primitives in rx.
Put aside of availability, if you're depends on rxjs, what reason you'd like to not to specify it as dependency?
Looks like using Webpack's tree shaking feature did it for me.
https://webpack.js.org/guides/tree-shaking/
My Webpack configuration:
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: ['./src/index.js'],
output: {
filename: './dist/dist.bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader" ,
query: {
presets: ['env'],
plugins: ["transform-object-rest-spread"]
}
}
]
},
plugins: [
new UglifyJSPlugin()
]
}
And specified the location of the import like:
import { Subject } from "rxjs/subject"
Rather than
import { Subject } from "rxjs"
Bundle size went from 213kb to 14kb

How can I use a static helper function(javascript) in SCSS to set the base url for images for different environments?

In my SCSS file I need to use different base urls for different app environments which will be prepended to the image name.
Example:
For production environment
background: url(/prod/image.png);
For development environment
background: url(/dev/image.png);
The helper function which I'm using in the rest of my app returns the base path of the static assets and it looks like this:
static imagePath() {
let imagesPath;
if (this.isProduction()) {
basePath = '/prod';
} else {
basePath = '/dev';
}
return basePath
}
How to achieve this?
Edit:*
I'm using extract-text-webpack-plugin which won't let me output multiple css files.
For example you can have 2 main files (dev.scss and prod.scss) that will look like:
// prod.scss
$basePath: '/prod';
#import "style.scss";
and same for dev.scss.
Otherwise you can use some placeholder for path prefix and substitute it with actual prefix on post-processing step. For example you can use this plugin for PostCSS.
UPDATE:
Following discussion in comments here is (untested) example of how webpack configuration may look like:
module.exports = {
// ....
module: {
rules: [
// ....
{
test: /\.scss$/,
use: {
loader: StringReplacePlugin.replace({
replacements: [
{
pattern: /{urlPrefix}/ig,
replacement: () => process.env.NODE_ENV !== 'production' ? '/dev' : '/prod',
}
]
}, 'sass-loader'),
}
},
// ....
],
},
plugins: [
new StringReplacePlugin(),
// ....
],
// ....
};

Is it possible to strip special characters from filenames in webpack?

Long story short, I cannot have certain characters like hyphens in our asset filenames. I'm not having the best of luck parsing through webpack documentation to figure out if it is possible to rename a file using a regex or something similar so I can strip out any hyphens from 3rd party packages where I do not control the source filename.
My super naive example would be something like this:
{
test: /\.(ttf|eot|woff|woff2)$/,
loader: `url-loader?limit=${ASSETS_LIMIT}&name=fonts/[name.replace(/-/)].[ext]`
}
Does anyone know if this is possible or how one would approach this requirement? Thanks!
The answer to this riddle appears to be found in the customInterpolateName loader option. With webpack#v3.4.1 the below was my end result for removing a hyphen.
This was the key tidbit:
plugins: [
// ... other plugins ...
new webpack.LoaderOptionsPlugin({
options: {
customInterpolateName: (loaderContext) => {
return loaderContext.replace(/-/g, '');
}
}
})
]
Here's a more complete example to give some context (note: the .css was appended to the font filenames intentionally as a workaround for yet another web resource name restriction in Dynamics CRM):
module.exports = {
// ... other config ...
module: {
loaders: [
// ... other loaders ...
{
test: /\.(ttf|eot|woff|woff2)$/,
loader: `url-loader?limit=${ASSETS_LIMIT}&name=fonts/[name].[ext].css`
}
]
},
plugins: [
// ... other plugins ...
new webpack.LoaderOptionsPlugin({
options: {
customInterpolateName: (loaderContext) => {
return loaderContext.replace(/-/g, '');
}
}
})
]
};

Typescript: How to have some imports in the global scope?

Context:
I work on a project where the senior programmer decided to reduce the boilerplate code in newly created typescript files. Two examples of this boilerplate code would be importing the React library or the function that fetches and processes our localized strings.
Question:
Is it possible to have imports always available in files placed in certain folders without having to write the import tags every time?
What I've tried:
I've searched and read on the subject and found those links that talk about defining variables to use in the global space:
global.d.ts, global-modifying-module.d.ts, A typescript issue that seems to get it working
However, I was still unable to get it to work. Here is what I've tried:
At the root of the folder where I want React to be always available, I created a global.d.ts file which contains:
import * as R from "react";
declare global{
const React: typeof R;
}
With this file, the resource "React" is supposed to always be available to other files in subsequent folders. My IDE (Webstorm) recognizes that the import is there and allows me to manipulate the variable React without complaining. However, when I try to run the app, I get this error:
ReferenceError: React is not defined
I don't understand what is wrong with the code! Here is an example of the file I'm trying to render:
export default class World extends React.Component<{}, any> {
public render() {
return (<div>Hello world</div>);
}
}
From this stackoverflow question, I was under the impression that the problem could be webpack related. For the sake of completeness, here is the webpack config file we're currently using:
const webpack = require('webpack');
const path = require('path');
const BUILD_DIR = path.resolve(__dirname, './../bundles');
const WEBPACK_ENTRYFILE = path.resolve(__dirname, './../srcReact/ReactWrapper.tsx');
// `CheckerPlugin` is optional. Use it if you want async error reporting.
// We need this plugin to detect a `--watch` mode. It may be removed later
// after https://github.com/webpack/webpack/issues/3460 will be resolved.
const { CheckerPlugin } = require('awesome-typescript-loader');
const config = {
entry: [WEBPACK_ENTRYFILE],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.less']
},
output: {
path: BUILD_DIR,
filename: 'bundle.js'
},
plugins: [
new CheckerPlugin()
],
devtool: 'source-map', // Source maps support ('inline-source-map' also works)
module: {
loaders: [
{
loader: 'url-loader',
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.(ts|tsx)$/,
/\.css$/,
/\.less$/,
/\.ttf/,
/\.woff/,
/\.woff2/,
/\.json$/,
/\.svg$/
],
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
loader: 'url-loader',
test: /\.(ttf|woff|woff2)$/
},
{
loader: "style-loader!css-loader!less-loader",
test: /\.less$/
},
{
loader: "style-loader!css-loader",
test: /\.css$/
},
{
loader: "svg-loader",
test: /\.svg$/
},
{
loader: "json-loader",
test: /\.json$/
},
{
loader: "awesome-typescript-loader",
test: /\.(ts|tsx)$/
}
]
}
};
module.exports = config;
I am certain I am missing something. Can anyone help me?
Surely already open followed a tutorial like this
To do this creates a vendor file where you import these types of "global".
./src/vendors.ts;
import "react";
Add this file a to first place at entry parameter:
entry: { 'vendors': './src/vendors.ts', 'main': './src/main.ts' }
And add CommonChunkPlugins:
plugins: [ new CommonsChunkPlugin({
name: 'vendors'
}),
Like this in AngularClass with polyfills.

Categories