How to use Material Components for the web with Webpacker - ruby-on-rails

Rails 5.2.1 webpacker4.0
app/javascript/application.scss
#import "material-components-web/material-components-web";
I use webpacker with the default setting, but it does not work well.
What additional settings do I need?
I want to use material-components-web in webpacker
err
Module build failed:
#import "#material/base/mixins";
File to import not found or unreadable: #material/base/mixins.
webpack/environment.js
const { environment } = require('#rails/webpacker')
const webpack = require('webpack')
const { VueLoaderPlugin } = require('vue-loader')
const vue = require('./loaders/vue')
environment.plugins.append('VueLoaderPlugin', new VueLoaderPlugin())
environment.loaders.append('vue', vue)
module.exports = environment

Related

Using <style lang="scss"> in vue component gives error

I am trying to use vue js in rails.
Everything works, except when I tried to use <style> inside .vue component
The exact error is:
./app/javascript/layouts/dashboard.vue?vue&type=style&index=0&lang=scss& (./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/sass-loader/dist/cjs.js??ref--1-2!./node_modules/style-loader/dist!./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src??ref--5-2!./node_modules/sass-loader/dist/cjs.js??ref--5-3!./node_modules/vue-loader/lib??vue-loader-options!./app/javascript/layouts/dashboard.vue?vue&type=style&index=0&lang=scss&)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Expected newline.
My environment.js file
const { environment } = require('#rails/webpacker')
const { VueLoaderPlugin } = require('vue-loader')
const vueLoader = require('./loaders/vueLoader')
const vuetifyLoader = require('./loaders/vuetifyLoader')
environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())
environment.loaders.prepend('vue', vueLoader)
environment.loaders.prepend('vuetify', vuetifyLoader)
const resolver = {
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
}
environment.config.merge(resolver)
module.exports = environment
VuetifyLoader.js file
module.exports = {
test: /\.s(c|a)ss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
// Requires sass-loader#^7.0.0
options: {
implementation: require('sass'),
fiber: require('fibers'),
indentedSyntax: true // optional
},
// Requires sass-loader#^8.0.0
options: {
implementation: require('sass'),
sassOptions: {
fiber: require('fibers'),
indentedSyntax: true // optional
},
},
},
],
}
install these two plugins.
npm install --save node-sass
npm install --save sass-loader
So, the problem was with fiber and indentedSyntax. After removing those two, everything works as expected. I was getting lots of error related to scss like
like
expected new line
in sass files inside node_modules. I don't know, why vuetify recommends to use fiber in sass loader.

Rails Webpacker - How to access objects defined in webpack entry file from views [HTML file]

I have a Rails 6 application and using Webpacker for assets.
I have the following code in file app/javascript/packs/application.js :
export var Greeter = {
hello: function() {
console.log('hello');
}
}
And I have the following script in one of my view (HTML) file:
<script>
$(document).ready(function(){
Greeter.hello();
});
</script>
Note: I am using JQuery and it is working fine.
I am getting the following error:
Uncaught ReferenceError: Greeter is not defined.
How can we use libraryTarget and library to expose the bundled modules, so that it can be accessed from HTML files as well ?
Or, is there any other way of doing it using Rails Webpacker ?
Any help would be much appreciated!
To do this without directly mutating the window object in your application code, you'll want to export Greeter as a named export from your application.js pack and extend the Webpack config output to designate the library name and target var (or window will also work).
// config/webpack/environment.js
environment.config.merge({
output: {
library: ['Packs', '[name]'], // exports to "Packs.application" from application pack
libraryTarget: 'var',
}
})
// app/javascript/packs/application.js
export {
Greeter
}
<script>
$(document).ready(function(){
Packs.application.Greeter.hello();
});
</script>
The library name is arbitrary. Using the [name] placeholder is optional but allows you to export to separate modules if you're using multiple "packs".
As I cannot comment rossta's answer, here is what I had to do. My default config was:
// config/webpack/environment.js
const { environment } = require('#rails/webpacker')
module.exports = environment
and I just had to add the additionnal config in it:
// config/webpack/environment.js
const { environment } = require('#rails/webpacker')
environment.config.merge({
output: {
library: ['Packs', '[name]'], // exports to "Packs.application" from application pack
libraryTarget: 'var',
}
})
module.exports = environment
After that, as mentioned by rossta, each symbol which is exported in app/javascript/packs/application.js can be accessed from the DOM as Packs.application.<symbol>.
in app/javascript/packs/application.js:
import Greeter from '../greeter.js'
Greeter.hello()
and in app/javascript/greeter.js:
export default {
hello : function(){
console.log('hello')
}
}
I could fix the issue exposing Greeter object to window as follows:
export var Greeter = {
hello: function() {
console.log('hello');
}
}
window.Greeter = Greeter;
However, I am still looking for a Webpack way of accomplishing this.

Rails 6 + Webpacker 4 + PostCSS & #font-face + Local fonts

I'm trying to import fonts in my rails 6 app for hours now.
It's a fresh app using Rails 6, Webpacker 4 and PostCSS.
Everything is loaded (with no error) through webpack (css, js, images). Compilation is correct. Image are properly displayed (using css background:url).
OTF/EOT/WOFF fonts : Compiled properly and fonts inside my #font-face are loaded and salted by Webpack. The font are not rendered properly in view (I got the default browser font instead).
I think I tried everything I know. I Switched file-loader for url-loader and back, with no success. Changed the folders hierachy, tried different fonts files, absolute urls (resolve-url-loader). Nothing seems to work.
Anyone would be kind enough point me to the right direction or to share a working config of local fonts loading with webpacker on rails 6 and PostCSS ?
Thank you in advance for your help.
Here is my config :
javascript > fonts
raleway_thin-webfont.woff
javascript > packs > application.js
require.context('../fonts/', true, /\.(eot|ttf|woff|woff2|otf)$/i);
import "./application.pcss";
import "js";
require("#rails/ujs").start();
require("turbolinks").start();
require("#rails/activestorage").start();
require("channels");
javascript > packs > application.pcss
#font-face {
font-family: 'Raleway';
src: url('../fonts/raleway_thin-webfont.eot'), format('eot');
}
#font-face {
font-family: 'Amaranth';
src: url('../fonts/Amaranth-Regular.otf'), format('otf');
}
#test-div { font-family: 'Raleway'; }
/postcss.config.js
module.exports = {
plugins: [
require('postcss-import'),
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
})
]
};
/config > webpack > environment.js
const webpack = require("webpack");
const { environment } = require("#rails/webpacker");
const { VueLoaderPlugin } = require("vue-loader");
const vue = require("./loaders/vue");
// const url = require('./loaders/url');
environment.plugins.append(
"Provide",
new webpack.ProvidePlugin({
jQuery: "jquery",
$: "jquery",
Tether: "tether",
tether: "tether",
Popper: ["popper.js", "default"]
})
);
["css", "moduleCss"].forEach(loaderName => {
const loader = environment.loaders.get(loaderName);
loader.test = /\.(p?css)$/i;
environment.loaders.insert(loaderName, loader);
});
environment.plugins.prepend("VueLoaderPlugin", new VueLoaderPlugin());
environment.loaders.prepend("vue", vue);
// environment.loaders.prepend("url", url);
// avoid using both file and url loaders
// environment.loaders.get("file").test = /\.(tiff|ico|svg)$/i;
module.exports = environment;
/config > webpack > loaders > url (not in use)
module.exports = {
test: [/\.eot$/, /\.otf$/, /\.ttf$/, /\.woff$/, /\.woff2$/],
use: [
{
loader: "url-loader",
options: {
limit: 10000,
name: "[name]-[hash].[ext]"
}
}
]
};

How to configure webpack devServer port?

I'm trying to use webpack in my Symfony app in docker, but I'm still getting error:
GET http://localhost:8000/sockjs-node/info?t=1556798329924 404 (Not Found)
Everything works fine axcepts this error...
App is running on port 8000 and node on port 8081. The address with 8081 port is accessible, but how can I tell webpack to use port 8081 with devServer?
Here is my webpack.config.js:
const Encore = require('#symfony/webpack-encore');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const outputPath = './public/build/';
const publicPath = '/build';
Encore
.setOutputPath(outputPath)
.setPublicPath(publicPath)
// Clean output dir before build
.cleanupOutputBeforeBuild()
.splitEntryChunks()
.enableSingleRuntimeChunk()
// uncomment if you're having problems with a jQuery plugin
.autoProvidejQuery()
// Generate JS files
.addEntry('loader', './assets/javascript/loader.js')
.addEntry('admin-loader', './assets/javascript/admin.js')
// Generate CSS files
.addStyleEntry('forms', './assets/styles/forms.scss')
.addStyleEntry('grid', './assets/styles/grid.scss')
.addStyleEntry('reboot', './assets/styles/reboot.scss')
.addStyleEntry('styles', './assets/styles/styles.scss')
.addStyleEntry('utilities', './assets/styles/utilities.scss')
.addStyleEntry('admin', './assets/styles/admin.scss')
.enableEslintLoader()
.configureTerserPlugin((options) => {
options.cache = true;
options.parallel = true;
options.terserOptions = {
output: {
comments: false,
}
}
})
.configureSplitChunks((options) => {
options.chunks = 'all',
options.maxInitialRequests = Infinity,
options.cacheGroups = {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
return `pckg.${packageName.replace('#', '')}`;
},
}
}
})
// Enable SASS loader with PostCSS config
.enableSassLoader()
.enablePostCssLoader()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
// CSS Hot Loader for HMR in webpack dev server
.addLoader({
enforce: 'post',
test: /\.(s?c|sa)ss$/,
exclude: /node_modules/,
loader: 'css-hot-loader',
})
.addPlugin(new StyleLintPlugin({
lintDirtyModulesOnly: Encore.isProduction(),
context: './assets/styles/',
quiet: false,
}));
const config = Encore.getWebpackConfig();
// Export settings and generate files
module.exports = config;
Does anyone know?

Rails Webpacker internal assets aren't proxied to action_controller.asset_host

I am using Rails 5.1 and Webpacker. It all works fine. I am using images inside my react components that are in /app/javascripts/images, and I import them fine into my components and all is well on development.
However - when I deploy, the internal images are now served directly from my site url (with their webpacker compiled paths, but the problem is I have set up my production environment to use an asset_host - so Rails is correctly prefixing all my other usual Rails image assets (including my react JS packs) - so they are all being served correctly from my asset_host.
JUST the internal images that are in /app/javascripts/images that I imported into my react components - they AREN'T being proxied through the asset_host. (it works fine in development - as I don't use an asset_host there).
How can I let webpacker know, that I need the images proxied through an asset_host on production?
You can add an environment argument "process.env.WEBPACKER_ASSET_HOST" to /config/webpack/production.js file.
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
process.env.WEBPACKER_ASSET_HOST = process.env.WEBPACKER_ASSET_HOST || '/yourpath/'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
i am working in rails6. hope this can help someone
I managed top set up my config/webpack/environment.js file up like this:
const { environment } = require('#rails/webpacker')
const env = process.env.NODE_ENV || 'development'
const { resolve } = require('path')
const { safeLoad } = require('js-yaml')
const { readFileSync } = require('fs')
const filePath = resolve('config', 'webpacker.yml')
const appConfig = safeLoad(readFileSync(filePath), 'utf8')[env]
const config = appConfig
const removeOuterSlashes = string =>
string.replace(/^\/*/, '').replace(/\/*$/, '')
const formatPublicPath = (host = '', path = '') => {
let formattedHost = removeOuterSlashes(host)
if (formattedHost && !/^http/i.test(formattedHost)) {
formattedHost = `//${formattedHost}`
}
const formattedPath = removeOuterSlashes(path)
return `${formattedHost}/${formattedPath}/`
}
const fileLoader = environment.loaders.get('file')
fileLoader.use[0].options.publicPath = formatPublicPath(process.env.WEBPACKER_ASSET_HOST, config.public_output_path)
module.exports = environment
According to the following comment here: https://github.com/rails/webpacker/issues/1186#issuecomment-358110765

Resources