How to import sortablejs properly with webpacker? - webpacker

I am trying to import sortablejs by using webpacker gem in rails, but no luck so far.
With these settings I get error Sortable is not defined.
Imported it like this in javascript/packs/application.js
import 'sortablejs';
this is my config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery',
jquery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default'],
List: 'list.js',
Sortable: 'sortablejs',
}))
module.exports = environment
I am aware of window.Sortable = Sortable; in application.js(works like that) but I am trying to avoid that, and expose Sortable somehow cleaner through webpacker if possible?
Any help/tips on how to debug and check what is wrong, or how to setup it correctly are most welcome.

Related

Ruby on Rails with React Webpack - defining/accessing environment variables?

I have created an app which uses Rails and a React front-end (rails new my-app --webpack=react)
I've worked with Rails and React separately before but never when integrated this way.
As the app is served on rails s, my understanding is that this is essentially working as a rails app which is rendering React components, so I believe be that the environment variables would be defined in config/application.yml rather than a .env, but I have tried both and can't get access to them in the React components
What I have tried
variables in .env and application.yml
dotenv-webpack
webpack DefinePlugin
adding my env files in config/webpack/environment.js
Prefixing with REACT_APP
Hardcoding the variable into the webpack config
I'm running the rails server as well as ./bin/webpack-dev-server, and also run "webpack --config webpack.config.js" before starting the servers.
My webpack.config.js
const Dotenv = require('dotenv-webpack');
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: path.resolve(__dirname, '') + '/app/javascript/packs/index.jsx',
plugins: [
new Dotenv(),
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify('5fa3b9'),
BROWSER_SUPPORTS_HTML5: true,
TWO: '1+1',
'typeof window': JSON.stringify('object'),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.REACT_APP_LAST_FM_API_KEY': JSON.stringify('myApiKeyfs89fs08a0')
})
],
module: {
rules: [
{ test: /\.jsx$/, use: {loader:'babel-loader'} },
{ test: /\.js$/, use: {loader:'babel-loader'} }
]
},
node: {fs:"empty"},
output: {
publicPath: '/'
}
};
In the end, I didn't need to do any of the above things. I just needed the .env file and to add
const dotenv = require('dotenv')
dotenv.config()
to my config/webpack/development.js

how to install inputmask on rails 6 with webpacker using jquery dependency

I'm trying to install inputmask on Rails 6 via webpacker. Currently getting following error:
Uncaught TypeError: $el.inputmask is not a function
current setup, compiles with not issues.
app/javascript/packs/application.js
require("jquery")
require("inputmask")
require("inputmask/dist/inputmask/inputmask");
require("inputmask/dist/inputmask/inputmask.numeric.extensions");
require("inputmask/dist/inputmask/inputmask.date.extensions");
require("inputmask/dist/inputmask/jquery.inputmask");
config/webpack/alias.js
const path = require('path')
module.exports = {
resolve: {
alias: {
"./dependencyLibs/inputmask.dependencyLib": "./dependencyLibs/inputmask.dependencyLib.jquery",
}
}
}
config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const aliasConfig = require("./alias")
const webpack = require('webpack')
environment.config.merge(aliasConfig)
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery'
})
)
module.exports = environment
I have seen quite a few examples out there but nothing seems to be working.
I think the most common setup for jquery is to install it with yarn:
yarn add jquery
Then in environment.js
(...)
environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}));
(...)
No need for require("jquery") in app/javascript/packs/application.js
Inputmask install:
yarn add inputmask
In app/javascript/packs/application.js
import 'inputmask';
Use
require("inputmask").default

How to make jquery available to sprockets using Webpacker?

I've just started experimenting with Webpacker within an existing app.
From all that I've read, my understanding is that Webpacker and Sprockets can co-exist, and that libraries compiled in Webpacker (e.g., jquery) can be made available to Sprokets via global variables.
But all my jquery in the asset pipeline are raising ReferenceError: Can't find variable: $
Have I misunderstood, or is there a bug in my code?
I've added jquery
yarn add jquery
and assigned the variables in environment.js
const { environment } = require('#rails/webpacker');
const webpack = require('webpack');
environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}));
module.exports = environment;
this works:
#javascript/packs/application.js
$(function () {
console.log('Hello World from Webpacker via JQUERY');
});
this does not
#assets/javascripts/application.js
$(function () {
console.log('Hello World from Sprockets via JQUERY');
});
# ReferenceError: Can't find variable: $
What is the expected behaviour?
In the end it is relatively easy to expose jQuery to global from within webpacker. But finding documentation on how to do this was very difficult! Hopefully, this can save someone else a search.
Add expose-loader
yarn add expose-loader -D
And then add the following configuration to config/webpack/environment.js
environment.loaders.append('expose', {
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: '$'
}, {
loader: 'expose-loader',
options: 'jQuery',
}]
})
I was then able to remove jquery from the asset pipeline, restart the server, and all my remaining jquery functions within sprockets continue to function as expected.

How to skip Javascript output in Webpack 4?

I use Webpack 4 in a project where I only need to compile and bundle styles so far. There's no Javascript.
Here's the config I have:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: {
'css/bundle': path.resolve(__dirname, 'static/scss/index.scss'),
},
output: {
path: path.resolve(__dirname, 'static'),
},
module: {
rules: [
{
test: /\.s[ac]ss$/,
include: path.resolve(__dirname, 'static/scss'),
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
],
},
plugins: [
new MiniCssExtractPlugin(),
],
};
The problem is that it outputs two files: bundle.css and bundle.js. Is there a way to configure Webpack so that it doesn't output the Javascript bundle? I tried to navigate the docs, tried a dozen different things, but it didn't really work.
One important note here is that if I remove the css-loader, bundling fails. So while css-loader is most likely responsible for outputting the bundle.js file, I'm not entirely sure how to avoid using it.
webpack-extraneous-file-cleanup-plugin has no effect with webpack 4.12.0.
I can suggest to remove bundle.js manually with on-build-webpack plugin:
var WebpackOnBuildPlugin = require('on-build-webpack');
// ...
plugins: [
// ...
new WebpackOnBuildPlugin(function () {
fs.unlinkSync(path.join('path/to/build', 'bundle.js'));
}),
],
March 2021:
In Webpack 5, on-build-webpack plugin did not work for me.
I found this:
Webpack Shell Plugin Next
The project I’m working on we’re using Webpack 5 as a build tool for a CSS pattern library. Therefore, we didn’t need the main.js in our dist.
Run npm i -D webpack-shell-plugin-next
Then in webpack.config.ts (just showing the pertinent parts):
import WebpackShellPluginNext from "webpack-shell-plugin-next";
module.exports = {
output: {
path: path.resolve(__dirname, "static/dist")
},
plugins: [
// Run commands before or after webpack 5 builds:
new WebpackShellPluginNext({
onBuildEnd: {
scripts: [
() => {
fs.unlinkSync(path.join(config.output.path, "main.js"));
}
]
}
})
]
};
export default config;
Unfortunately, this is just the way that webpack currently works. However, we are not alone in this problem! There's a plugin to cleanup any unwanted files:
install the plugin:
yarn add webpack-extraneous-file-cleanup-plugin -D
and then in your config:
const ExtraneousFileCleanupPlugin = require('webpack-extraneous-file-cleanup-plugin');
plugins: [
new ExtraneousFileCleanupPlugin({
extensions: ['.js'],
minBytes: 1024,
paths: ['./static']
}),
]
I simply delete the unneeded output with rm in package.json:
"scripts": {
"build": "npm run clean && webpack -p && rm ./dist/unneeded.js"
},
The webpack-remove-empty-scripts plugin, compatible with webpack 5, cover the current issue. It remove unexpected empty js file.

How to use jquery ui with bower?

I'm experimenting with yeoman and bower.
I have created a yeoman webapp using the following command
yo webapp
I want to use jqueryui so I have installed it using bower:
bower install jquery-ui --save
This works fine, but the jQuery UI component doesn't contain a javascript file with "all" the components, it just contains a lot of javascript files, one for each component.
Should I include only the javascript files that I need? Or should I do something else before using jQuery UI?
Thanks for the tips!
Added jquery-ui in dependencies of bower.json (or component.json) along with jquery.
{
…,
"dependencies": {
"jquery": "~1.9.1",
"jquery-ui": "~1.10.3",
...
},
…
}
Install them:
bower install
Then, added path to jqueryui In main.js and require it:
require.config({
paths: {
jquery: '../components/jquery/jquery',
jqueryui: '../components/jquery-ui/ui/jquery-ui',
…
},
shim: {
jqueryui: 'jquery',
…
},
…
});
require(['app', 'jquery', 'jqueryui', 'bootstrap'], function (app, $) {
'use strict';
...
});
It works for me.
In the latest jQuery UI bower component as we speak (v. 1.10.3), you can do the following:
For the CSS themes, include the following link:
<link rel="stylesheet" href="bower_components_path/jquery-ui/themes/base/jquery-ui.css">
To get the most components and widgets of jQueryUI running, include the following script:
<script src="bower_components_path/jquery-ui/ui/jquery-ui.js" ></script>
For reference, bower install jquery-ui --save would add the jquery-ui.js dependency to the project, but not the styles. For that I needed to add to the bower.json file an overrides section, as below
{
...,
"dependencies": {
...,
"jquery-ui": "^1.11.4" // already added with --save from bower install command
},
...,
"overrides": {
"jquery-ui": {
"main": [
"themes/smoothness/jquery-ui.css",
"jquery-ui.js"
]
}
}
}
References:
https://stackoverflow.com/a/27419553/4126114
https://github.com/taptapship/wiredep/issues/86
I would just include the files that I need or use the default custom build in the folder (which I believe has all the components) if you require everything or if it's just for experimentation.
<script src="components/jqueryui/ui/jquery-ui.custom.js"></script>
At this time bower pulls down the entire repo and since (from their website) "bower is just a package manager" anything else needed like concatenation or module loading is handled by other tools like sprockets/requirejs.
References:
Using packages with bower on homepage http://bower.io/
Dissusion about bower and pulling entire repos
https://github.com/bower/bower/issues/45
You could use requirejs.config's shim property to achieve your goal:
requirejs.config({
shim: {
'jquery.ui.sortable': {
deps: ['jquery', 'jquery.ui.core', 'jquery.ui.widget', 'jquery.ui.mouse', 'jquery.ui.position'],
exports: '$'
}
}
});
We specified, that jquery.ui.sortable, when required in your project, needs to load and execute the modules listed under deps first, before being executed itself.
Unfortunately, this still produces a race condition... But that is generally how one would go about this (:

Resources