Import Javascript files as a string? - javascript

I want to be able to simply do an import file from 'file.js and then have file be a string of the contents within file.js. I've toyed around with raw-loader but it doesn't give me the same contents (instead it loads it in a different format). Any suggestions?

it doesn't give me the same contents (instead it loads it in a different format)
That seems to mean that there are other loaders from your config applied to the file. You can enforce that only the loader in the import statement is used by prefixing it with a !:
import file from '!raw-loader!file.js'
From the docs:
It's possible to overwrite any loaders in the configuration by prefixing the entire rule with !.

In Webpack 5 it's possible to handle it without raw-loader.
It's enough to add a rule with type: asset/source (see the docs). Note that in this case, if you use babel loader or other JS loaders, the code will still be processed by them if not overridden manually.
A simplified code example:
module: {
rules: [
{
test: /(?<!boilerplate)\.js$/, // a negative look-behind regex to exclude your file
exclude: /node_modules/, // also can be handled here, adding a folder with file(s) to be excluded
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /boilerplate\.js$/,
type: 'asset/source'
},
]
}

Related

CSS into JS using webpack

I`m trying to paste a CSS Code into a JS File using webpack
My flux is the following
SASS file > CSS content > PostCSS > css file
{
test: /\.(sass|scss)$/,
exclude: /node_modules/,
use: [
MiniCSSExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader: 'sass-loader',
options: {
sourceMap: true,
sassOptions: {
outputStyle: 'compressed'
}
}
}
]
}
But the MiniCSSExtractPlugin gets me the content into a css file.
I'm use Lit Element so the styles should be declare with css function part of lit-element on the following way
import {css} from 'lit-element';
export default css`
:host {
display: inline;
}
`;
Is there any way to generate css code as a string and paste it into js file?
To import a CSS file into JS (w/webpack) you need to configure webpack with the following loaders:
css-loader
style-loader
Both available with NPM:
$ npm i css-loader style-loader --save-dev
And add this entry to the module.rules array in your webpack configuration:
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
The result
Both of this loaders correctly configured will allow you to do the following sentence in JavaScript:
import myStyles from './your-css-file.css';
And then, you can just paste them into literal templates as follows:
static get styles() {
return css`${myStyles}`;
}
Additionally:
With a deep knowledge into what you might be talking about, you might need to take a look around #cells/cells-cli files and add those loaders into webpack configuration. Otherwise, you may need to create a webpack.config.js file in every lit-element component, which might not be the best for the current architecture.
Nice to see you around here, ¡saludos!;)
#k3llydev, I tried your suggestion and couldn't get it to work. Do you have any suggestions, specifically when you say "both of these loaders correctly configured will allow you to do the following"? I'd like to be able to import the CSS and then use it directly in the styles getter like you show in your example, but I had to do this as a workaround:
import MyImportedStyle from './some.css';
static get styles () {
return [
css`${unsafeCSS(MyImportedStyle.toString())}`
];
}
While using the 'to-string-loader' in webpack:
{
test: /\.css$/i,
use: ['to-string-loader', 'css-loader'],
}
This worked out for me and did what I wanted, but if I could avoid using the to-string-loader and could use the imported object directly, that would be idea. Any suggestions?
This way should do what the original poster asked for, a way to get the CSS as a string and use it in your LitElement.

How to import dynamically with webpack

I want to use FontAwesome's icons, but the whole package is too large and I have to select only the ones that I'm using
I'm using vue & webpack
Right now I have the standard:
import { library } from '#fortawesome/fontawesome-svg-core'
import { faGem as falFaGem, faDatabase as falFaDatabase } from '#fortawesome/pro-light-svg-icons'
import { faGem as farFaGem } from '#fortawesome/pro-regular-svg-icons'
import { faGem as fasFaGem } from '#fortawesome/pro-solid-svg-icons'
library.add(falFaGem, falFaDatabase, farFaGem, fasFaGem)
The thing is I have around 80 (for now) icons and some of them duplicates like faGem in the example, hence the "faGem as farFaGem"
I tried importing FAS from '#fortawesome/pro-regular-svg-icons' and making a foreach and adding to library only the icons that I need but webpack imports the whole package into the compiled code
Is there an easier, cleaner way to achieve this?
I believe that the title to your question is a bit wrong. What you want to achieve is reduce the size of the FontAwesomes npm package and that is something that can be achieved in different ways.
The most common way nowadays is using Treeshaking. Basically, your code will be '''analysed''' and a graph of dependencies will be generated, before giving you the "compiled" version of your code it will remove all those modules that were not used from FontAwesome.
FontAwesome can perform TreeShaking if your tool (webpack) allows it, sadly it seems that there are some problems with Webpack 4 but they offer some work arounds like setting the variable modules false in your config:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: './bundle.js'
},
module: {
rules: [{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
use: {
loader: 'babel-loader',
options: {
presets: [
['#babel/preset-env', { modules: false }],
],
plugins: ['#babel/plugin-proposal-class-properties'],
}
}
},
]
}
};
In the other hand I believe that what you want to achieve is quite difficult (you will still need to declare all the icons that you want to use from FontAwesome (to use a require(...) call dynamically is something that the tree shaking algorithm can not work around and it will import the whole npm package), and the same for the name conflicts.
If you want it to be a bit cleaner, maybe declare and add all this icons in a separated file of your project, but as far as I can tell, there is no a better way to achieve what you want.

Loading SVGs within .scss with Webpack and svgr loader

Webpack config:
For a .svg I use config:{ test: /\.svg$/, use: ['svgr/webpack'] }
For .scss I use css-loader, postcss-loader and sass-loader
Folder structure:
I have folder structure that looks like this:
- App
-- styles
--- globals.scss // Here I import my partials
--- partials
---- _my_partial.scss
-- icons
--- svgs
---- my_icon.svg
svgr loader:
I like svgr loader as it allows me to just import my icon and use it as React component:
import MyIcon from './icons/svgs/my_icon.svg';
...
<MyIcon />
The actual problem:
I was fine with this approach but I have to get one of the svgs as a background-image, so inside _my_partial.scss I wrote:
background-image: url(../icons/svgs/my_icon.svg);
I am up just one folder in this url as when being up two, it complained that it cannot resolve it - I guess this is because I import my partials in my globals.scss.
With this setup all I get in the browser is:
GET http://localhost:3005/[object%20Module] 404 (Not Found)
svgr/webpack turns your svg into react components, so when using svg into scss it's actually an object / react component. Change svgr/webpack to file-loader in order to use that. If you want to still use both, you could try something like:
{ test: /\.react.svg$/, use: ['svgr/webpack'] }
{ test: /\.svg$/, use: ['file-loader'] }
then rename all the svg's that you want as React components to filename.react.svg and the rest just leave with .svg.
I haven't tested this though :)
UPDATE: Looking at the documentation (section: Handle SVG in CSS, Sass or Less), it seems you can use svgr/webpack with file-loader:
https://github.com/smooth-code/svgr/tree/master/packages/webpack
{
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
issuer: {
test: /\.jsx?$/
},
use: ['babel-loader', '#svgr/webpack', 'url-loader']
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader'
},
}
Either way, you probably need to make a few changes to fit in your needs but it supports it :)

Minify/Mangle CSS Classnames in JSX and CSS output from Webpack (or other programmatic means)

I'd like to minify my classnames (for very minimal source protection purposes) in both my output CSS files and in the rendered JSX from my React components similarly to this Webpack plugin: https://github.com/vreshch/optimize-css-classnames-plugin
Is there any existing option I can use to achieve this, either Webpack or otherwise? Thanks very much.
From:
<div className="long-class-name"></div>
.long-class-name {
}
To:
<div class="a"></div>
.a {
}
As you're already using Webpack, I think one good option is to use CSS Modules to accomplish that. You can use either css-loader or postcss-modules to do that, for example.
Basically, by using CSS Modules, you can import your CSS and treat it as a JSON. So, if you write .long-class-name { } you'll have something like this { 'long-class-name': '<<interpolated name>>' }. The trick here is that the <<interpolated name>> in my example is something you can set programmaticaly.
Webpack has some predefined tokens that you can use, as you can see here: https://github.com/webpack/loader-utils#interpolatename. And you can check an example here:
{
test: /\.css$/,
use: [
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
}
]
}
However, if you want something more "customized", you can specify a getLocalIdent function:
{
test: /\.css$/,
use: [
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
getLocalIdent: (context, localIdentName, localName, options) => {
return 'whatever_random_class_name';
}
}
}
]
}
Please, refer to the docs to read more about the options on CSS Modules.
Doing this way, you can specify your class names the way you need and solve your problem.
Hope that helps!
For anyone wanting to easily mangle classnames in Next.js, use my package!

webpack - how to stop the loader running twice?

All of my text imports in a big project are in the form:
var template = require('text!./foo.html');
I'd like to set webpack to automatically use text-loader, so I added the following to my config:
{ test: /\.html$/, loader: 'text-loader' }
Only problem is now my templates are being run through the loader twice, and I'm getting something like this in my bundle...
module.exports = 'module.exports = "<section class=\\"foobar\\" ...
How can I set the loader to only run once without removing all of the text! callouts from every one of my files? This isn't an option as I'm trying to migrate incrementally...
require('text!./foo.html') applies text-loader to the foo.html
{ test: /\.html$/, loader: 'text-loader' } applies text-loader to every html
Hence,your loader is applied twice.
You should remove text-loader from either of two and it will work fine

Categories

Resources