Enable inline javascript in LESS - javascript

I would like to use inline js in my less files but I get the following message:
Inline JavaScript is not enabled. Is it set in your options?
How can I enable that?

I had same problem, I use webpack with less loader, I needed to add javascript option in less loader config:
{
test: /\.less$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "less-loader",
options: {
javascriptEnabled: true
}
}]
}
I found in the sourcecode of less compiler: https://github.com/less/less.js/blob/3.x/bin/lessc
that they parse js less option in this way:
case 'js':
options.javascriptEnabled = true;
break;
case 'no-js':
console.error('The "--no-js" argument is deprecated, as inline JavaScript ' +
'is disabled by default. Use "--js" to enable inline JavaScript (not recommended).');
break;
So you should probably use '--js' in a static compilation ( command line ) or 'javascriptEnabled: true' in a dynamic compilation ( like webpack loader ) to enable javascript.

Just to update the accepted answer,
From 3.11.1, if you use just options, it will throw :
ValidationError: Invalid options object. Less Loader has been
initialized using an options object that does not match the API
schema.
- options has an unknown property 'javascriptEnabled'. These properties are valid: object { lessOptions?, prependData?,
appendData?, sourceMap?, implementation? }
In less#3.11.1, it's not just options that should be used, but lessOptions like this :
{
test: /\.less$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "less-loader",
options: {
lessOptions: {
javascriptEnabled: true
}
}
}]
}

Updated: May 2020
For less-loader version 6.1.0^.
In "less-loader" version 6.1.0^ they made breaking changes to the loader that, if you used something like Ant Design (or other LESS and JS loaders) you would nomally add the javascriptEnabled: true flag to the "options" object in your Webpack configuration.
In version 6.1.0^ this was change to be placed in the lessOptions object under the options configuration for the less loader. Here is the solution I used, that works for my Webpack configuration bundle.
module: { rules: [{
test: /\.less$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{
loader: "less-loader",
options: {
lessOptions: {
javascriptEnabled: true,
}
}
}
]
}]}
Notice that the javascriptEnabled flag is not under the top-level options object, but it, instead, under the lessOptions sub-object. That is the latest updated standard as of less-loader version 6.1.0^.

If you're using the lessc the cli interface then you just need --js on the end.
lessc --js ./styles/theme.less ./styles/theme.css

I got this problem when using the newest version of less. Then I switched to version 2.7 and I had it fixed.

Inline JavaScript was disabled by default for security concerns. What was happening is that online generators would sometimes allow configuration of Less variables that they then interpreted directly.
This was vulnerable to code injection, meaning that JavaScript could be injected into a Less style sheet that ran on a server directly.
For this reason, inline JavaScript has been deprecated (set to false by default in 3.x), and the replacement for that is the #plugin syntax and using a proper JS plugin. - (See: http://lesscss.org/features/#plugin-atrules-feature)
Yes, you can still set compilation options to javascriptEnabled: true, but this is not considered best practice for style sheets. In general, your style sheet should not have JS in it. It's better to use a plugin.

Yes to everything that #matthew-dean and #davide-carpini said... but for anyone looking for the Grunt-LESS code snippet here you go:
less: {
dev: {
options: {
paths: ['Content/less'],
plugins: [
new(require('less-plugin-autoprefix'))({
browsers: ['last 2 versions']
}),
new(require('less-plugin-clean-css'))({
sourceMap: true,
advanced: true
})
],
relativeUrls: true,
javascriptEnabled: true
},
files: {
'Content/less/site.css': 'Content/less/site.less'
}
}
},
this is working for my implementation using "grunt-contrib-less": "^2.0.0" ... your mileage may vary

I had the same problem but in vue-cli 4 + iVueUi theme customization. Maybe somebody has same troubles like me. And that's solution:
Create or use existing vue.config.js file at the root of your project. And add this code (or partically add) into it.
module.exports = {
css: {
loaderOptions: {
less: {
javascriptEnabled: true
}
}
}
};
But remember that js is disabled by default for security reasons. So that's at your own risk.

as i was using craco and craco-less and also customizing ant design's variable through my .less file ,modifying craco.config.js like below fixed my problem:
const CracoLessPlugin = require('craco-less');
module.exports = {
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
javascriptEnabled: true,
},
},
},
},
],
}

For any Vite 3 users out there, the following is how I enabled inline javascript for a project with less/react.
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
},
},
},
});
However, inline javascript is a deprecated feature on less (link)
False by default starting in v3.0.0. Enables evaluation of JavaScript inline in .less files. This created a security problem for some developers who didn't expect user input for style sheets to have executable code.

Related

Can't import the named export 'Directive' from non EcmaScript module (only default export is available)

this is a ionic angular project that i'm working on, i'm using ng-lazyload-image plugin Link. when i start compiling it showing errors like this.
Error: ./node_modules/ng-lazyload-image/fesm2015/ng-lazyload-image.mjs 401:10-19
Can't import the named export 'Directive' from non EcmaScript module (only default export is available)
This means your bundler resolves .mjs files, however it doesn't know that they are ESM modules. On webpack, you can add the following to rules.
webpack.config.js (in project root)
module.exports = {
configureWebpack: {
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: "javascript/auto"
}
]
}
}
}
https://webpack.js.org/configuration/
EDIT: Found a solution for craco.config.js
module.exports = {
webpack: {
configure: (webpackConfig) => {
webpackConfig.module.rules.push({
test: /\.mjs$/,
include: /node_modules/,
type: "javascript/auto"
});
return webpackConfig;
},
plugins: [
// Inject the "__DEV__" global variable.
new webpack.DefinePlugin({
__DEV__: process.env.NODE_ENV !== "production",
})
],
},
};
The answer of #Joosep.P works, but for someone with laravel and webpackmix the following is the way to go. In webpack.mix.js file add the following:
mix.webpackConfig({
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: "javascript/auto"
}
]
}
});
Just posting it as another answer as it may help someone else or me to find the solution with laravel and webpackmix easily in the future. Thanks.
It probably has to do with different Angular versions.
If ng-lazyload-image is using Angular 13 and your own project is using a lower version this will happen. There are some breaking changes since Angular 13.
If ng-lazyload-image is using Angular 13 there are no es2015 files generated for it's npm package and your compiler is still looking for them.
An option to solve this would be to use a lower version of the ng-lazyload-image package or update your own Angular to Angular 13+

Need to apply a loader to all dependencies of a certain file recursively

I am building a universal JavaScript application that relies on a single config file. The config contains mostly code that can be safely executed on the server and within the browser, but certain files and functions should be run server-side only.
I have built a Babel plugin that I use along with babel-loader and I apply this loader to the config file itself as well as any file that is required directly from the config using the issuer Webpack rule:
Relevant Webpack loaders:
{
test: paths.config,
use: [
{
loader: 'babel-loader',
options: {
plugins: [
[removeObjectProperties],
],
},
},
],
},
{
issuer: paths.config,
use: [
{
loader: 'babel-loader',
options: {
plugins: [
[removeObjectProperties],
],
},
},
],
},
removeObjectProperties Plugin:
function removeObjectProperties() {
return {
visitor: {
ObjectProperty: function ObjectProperty(path) {
if (['access', 'hooks'].indexOf(path.node.key.name) > -1) {
// Found a match - remove it
path.remove();
}
},
},
};
}
Using the above Webpack configuration, my removeObjectProperties plugin successfully removes all server-only properties from both the top-level config and any modules that are require'd directly from it.
The problem is that the issuer Webpack rule does not apply recursively. So, if I have a file that is required from a file that is required by the config, the loader is not applied.
I could use some guidance as to how to either better achieve my goals of recursively removing certain object properties through any unknown number of required modules, or determine some other way altogether of separating out server-side only code from code that will be bundled and served to browsers.
Thank you in advance!

Change default Laravel Mix Minimizer/Minifier (webpack)

Is there a way to change the default minifier that Laravel Mix uses?
By default, it uses 'Terser' (the Webpack default), but I would like it to instead use Closure Compiler (see here).
I have tried various things but have not had any luck yet. This is my latest failed attempt:
mix.webpackConfig({
module: {
rules: [
// ...
]
},
plugins: [
// ...
],
resolve: {
alias: {
// ...
}
},
optimization: {
minimizer: [
new ClosurePlugin({mode: 'STANDARD'}, {})
]
}
});
I would like to specifically achieve this using the webpack.mix.js configuration if possible i.e. I would like to avoid overriding the Laravel mix configuration (this may not be possible)

Webpack bundled JS not being executed

This is a very strange problem because actually, some of the bundled code is being executed. I use style loader for my CSS and that of course gets put into bundle.js and loads and works fine. However, I also have a file with some code to set up the jQuery localScroll plugin, and that code isn't working.
To test it, I included in the same file a call to console.log(), just telling it to write the number 4. If I open up bundle.js, I can see the console.log() call as well as the call to $.localScroll(), they just simply aren't running. Calling $.localScroll() manually from the console works as intended.
Here is the JS file in question:
console.log(4);
$(() => {
$.localScroll({duration: 800});
});
Here is my Webpack config:
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: './webpack-entry.js',
plugins: [
new CleanWebpackPlugin(['dist']),
new webpack.optimize.UglifyJsPlugin()
],
output: {
filename: './javascripts/bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|jpeg)$/,
use: {
loader: 'url-loader',
options: {
limit: 8192,
fallback: 'file-loader',
name: './images/[hash].[ext]'
}
}
},
{
test: /\.pug$/,
use: [
{
loader: 'file-loader',
options: {
name(file) {
if(new RegExp(/partials/).test(file)) {
return './views/partials/[name].[ext]'
}
return './views/[name].[ext]'
}
}
},
'pug-asset-loader?root=./src'
],
},
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['env'],
}
},
]
}
],
}
};
Finally, here is bundle.js (my custom code seems to be at the very bottom, in some sort of array of functions). The non-uglified version is too long for SO, so here it is on Hastebin: https://hastebin.com/vululimupi.js
The problem is that you haven't defined this dependency as a module. Rewriting it following supported module format specs should help.
After some testing, it seems that the essential problem is just as #uKolka was saying - my files were not getting required as modules. While I'm still not entirely certain why their code was still appearing in my bundle file but not running, I have found a way to still reap the recursive benefits of require.context(). It seems that require.context() returns a function which is itself capable of resolving the files it logs in whatever folder you have pointed it at. It also has a member function keys() which quite conveniently returns each dependent file name and is easily used with forEach().
Given all that, this is how my webpack-entry.js looks now:
import './src/stylesheets/scss/master.scss';
require.context('./src/views', true, /\.pug$/);
const js = require.context('./src/javascripts/', false, /\.js$/);
js.keys().forEach(key => js(key));
This works just fine.
In my case it was due to Babel and React. If you use React, then try to call ./src/index.js directly and use "#babel/preset-env", "#babel/preset-react" in your .babelrc. You can take a look at my gist. and in your webpack.config.js:
{
test: /\.js?$/,
use: ["babel-loader"],
exclude: /node_modules/
},
take a look at the gist:
https://gist.github.com/Nagibaba/14e898d99a4be89b00a60d28abc19bc0
For ruby's rails/webpacker users only.
This question title and content made me find it before this issue which may be the correct answers for some users here. To avoid link rot, I'll explain it shortly below:
Make sure your #rails/webpacker npm library and webpacker gem both have the same exact version.
I ended up doing:
IO.foreach("package.json").find { |line| line[%r("#rails/webpacker": "(.*?)")]}
gem "webpacker", Regexp.last_match(1).tr("-", ".")

Loading SASS Modules with TypeScript in Webpack 2

I have a simple project set up using TypeScript, ReactJS, and SASS, and would like to bundle it all using Webpack. There's plenty of documentation on how to achieve this with JavaScript and regular old CSS. However, I can't find any documentation that combines the loaders I need and uses Webpack 2 syntax (rather than the original Webpack syntax for loaders). Thus, I'm unsure of how to create the correct configuration.
You can find my webpack.config.js file here. How would I modify the configuration so that TypeScript accepts my SCSS modules, and so that Webpack properly bundles my SCSS with my TypeScript?
This may also be helpful: when I run Webpack at the moment, I get the following error:
ERROR in ./node_modules/css-loader!./node_modules/typings-for-css-modules-loader/lib?{"namedExport":true,"camelCase":true}!./node_modules/sass-loader/lib/loader.js!./src/raw/components/styles.scss
Module build failed: Unknown word (1:1)
> 1 | exports = module.exports = require("../../../node_modules/css-loader/lib/css-base.js")(undefined);
| ^
2 | // imports
3 |
4 |
# ./src/raw/components/styles.scss 4:14-206
# ./src/raw/components/greetings/greetings.tsx
# ./src/raw/index.tsx
# multi ./src/raw/index.tsx
ERROR in [at-loader] ./src/raw/components/greetings/greetings.tsx:3:25
TS2307: Cannot find module '../styles.scss'.
Note that ./src/raw/index.tsx is the entry point of my application, ./src/raw/components/greetings/greeting.tsx is my only React component, and ./src/raw/components/styles.scss is my only SCSS file.
The typings-for-css-modules-loader is a drop-in replacement for css-loader (technically it uses css-loader under the hood) and that means it takes CSS and transforms it to JavaScript. You're also using the css-loader, and that fails because it receives JavaScript, but expected CSS (as JavaScript is not valid CSS, it fails to parse).
Additionally, you are not using CSS modules, because you're not setting the modules: true option on the CSS loader (or typings-for-css-modules-loader, which passes it on to css-loader).
Your .scss rule should be:
{
test: /\.scss$/,
include: [
path.resolve(__dirname, "src/raw")
],
use: [
{ loader: "style-loader" },
{
loader: "typings-for-css-modules-loader",
options: {
namedexport: true,
camelcase: true,
modules: true
}
},
{ loader: "sass-loader" }
]
}
Here is a little extended version (since the above did somehow not work for me), using another package (css-modules-typescript-loader) derived from the stale typings-for-css-modules-loader.
In case anybody runs into the same problems - this is a configuration that works for me:
TypeScript + WebPack + Sass
webpack.config.js
module.exports = {
//mode: "production",
mode: "development", devtool: "inline-source-map",
entry: [ "./src/app.tsx"/*main*/ ],
output: {
filename: "./bundle.js" // in /dist
},
resolve: {
// Add `.ts` and `.tsx` as a resolvable extension.
extensions: [".ts", ".tsx", ".js", ".css", ".scss"]
},
module: {
rules: [
{ test: /\.tsx?$/, loader: "ts-loader" },
{ test: /\.scss$/, use: [
{ loader: "style-loader" }, // to inject the result into the DOM as a style block
{ loader: "css-modules-typescript-loader"}, // to generate a .d.ts module next to the .scss file (also requires a declaration.d.ts with "declare modules '*.scss';" in it to tell TypeScript that "import styles from './styles.scss';" means to load the module "./styles.scss.d.td")
{ loader: "css-loader", options: { modules: true } }, // to convert the resulting CSS to Javascript to be bundled (modules:true to rename CSS classes in output to cryptic identifiers, except if wrapped in a :global(...) pseudo class)
{ loader: "sass-loader" }, // to convert SASS to CSS
// NOTE: The first build after adding/removing/renaming CSS classes fails, since the newly generated .d.ts typescript module is picked up only later
] },
]
}
};
Also put a declarations.d.ts in your project:
// We need to tell TypeScript that when we write "import styles from './styles.scss' we mean to load a module (to look for a './styles.scss.d.ts').
declare module '*.scss';
And you will need all these in your package.json's dev-dependencies:
"devDependencies": {
"#types/node-sass": "^4.11.0",
"node-sass": "^4.12.0",
"css-loader": "^1.0.0",
"css-modules-typescript-loader": "^2.0.1",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"ts-loader": "^5.3.3",
"typescript": "^3.4.4",
"webpack": "^4.30.0",
"webpack-cli": "^3.3.0"
}
Then you should get a mystyle.d.ts next to your mystyle.scss containing the CSS classes you defined, which you can import as a Typescript module and use like this:
import * as styles from './mystyles.scss';
const foo = <div className={styles.myClass}>FOO</div>;
The CSS will automatically be loaded (injected as a style element into the DOM) and contain cryptic identifiers instead of your CSS classes in the .scss, to isolate your styles in the page (unless you use :global(.a-global-class) { ... }).
Note that the first compile will fail whenever you add CSS classes or remove them or rename them, since the imported mystyles.d.ts is the old version and not the new version just generated during compilation. Just compile again.
Enjoy.

Categories