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.
Related
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.
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
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
I am migrating from gulp/jspm to webpack. Everything is seemingly going fine by our SASS. In gulp our task looks like so:
var gulp = require('gulp');
var sourcemaps = require('gulp-sourcemaps');
var sass = require('gulp-sass');
var autoprefixer = require('autoprefixer');
var paths = require('../paths');
var flatten = require('gulp-flatten');
var postcss = require('gulp-postcss');
gulp.task('build-sass', () => {
return gulp.src(paths.sassSource)
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(postcss([autoprefixer()]))
.pipe(flatten())
.pipe(sourcemaps.write('/maps'))
.pipe(gulp.dest(paths.output + 'css'));
});
And thus works perfectly. This is my current webpack config for SASS:
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract({
fallbackLoader: 'style-loader',
loader: 'css-loader?sourceMap!postcss-loader!sass-loader?sourceMap',
}),
},
And in the plugins I have:
new ExtractTextPlugin({
filename: 'global.css',
allChunks: true,
}),
The problem is when I run webpack I get these SASS errors:
ERROR in ./~/css-loader?sourceMap!./~/postcss-loader!./~/sass-loader?sourceMap!./src/sass/base/_QB4-variables.scss
Module build failed:
$never-signed-in: $gray-light;
^
Undefined variable: "$gray-light".
in /Users/allen/work/TwentyTwenty.QualBoard.Web/src/sass/base/_QB4-variables.scss (line 31, column 19)
I am getting tons of those type of errors which I don't understand since the gulp sass tool never threw those errors before. I feel like some configuration is missing.
In my main.js file I was missing my sass include. Thus it was just compiling all that sass but with no particular order.
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 (: