Rails Webpacker no longer emitting CSS - javascript

I upgraded webpacker from (4.0.0.pre.3) to (4.0.2) and it doesn't seem to be emitting my CSS any longer. The screenshot shows the emit log with (4.0.0.pre.3) and(4.0.2) on the right.
My App.jsx is my entry point and it's importing a app.scss. I have the following in my babel.rc
{
presets: [
'#babel/preset-react',
['#babel/preset-env', {
targets: "last 2 versions"
}]
],
plugins: [
'#babel/plugin-proposal-class-properties',
'#babel/plugin-proposal-export-default-from',
['react-css-modules', {
'filetypes': {
'.scss': {
'syntax': 'postcss-scss'
}
},
'generateScopedName': '[name]__[local]--[hash:base64:5]'
}]
]
}
config/webpack/environment.js:
const { environment } = require('#rails/webpacker')
const merge = require('webpack-merge')
const customCssLoaderOptions = {
localIdentName: '[name]__[local]--[hash:base64:5]',
// minimize: environment.NODE_ENV === 'production',
modules: true
}
const CSSLoader = environment.loaders.get('sass').use.find(el => el.loader === 'css-loader')
CSSLoader.options = merge(CSSLoader.options, customCssLoaderOptions)
environment.config.set('entry.App', './app/javascript/packs/App.jsx')
module.exports = environment
I commented out the minimize option because it was causing the new version to break but I don't think that's causing my CSS to not be emitted altogether?
config/webpack/development.js:
const environment = require('./environment')
module.exports = environment.toWebpackConfig()

Not sure if this is the exact issue, but according to the Webpacker 4.x upgrade guide you're meant to replace a .babelrc file with a babel.config.js (amongst other changes).
I'm upgrading to 4.x also, however, and still not getting CSS emits even after all the steps described in that guide. If you managed to solve the issue, please return to share how.
EDIT:
My colleague just informed me that CSS files (in our Rails + Webpacker codebase, at least) now need to be filename.module.css, with the import statement updated to match of course.
Hope that helps someone else!

Not sure why Webpacker 4+ doesn't emit CSS files but you can emit them by updating line 20 in your config/webpacker.yml setting extract_css as true.
19 # Extract and emit a css file
20 extract_css: true

Related

NextJS: TailwindCSS not working in production

I’m using NextJS, TailwindCSS and Typescript. When running in development, everything works as expected, but when running in production, no tailwindcss classes are applied. Here is a link to the repo: https://github.com/Capsule-app/next.
This problems occurred because of Purge. Please check the official page
Few possible way to fixed this issues.
Option A (Quick & Dirty Plus Lazy) :
In tailwind.config.js file try purge: false
Option B:
If you are using purge: ["./pages/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,ts,jsx,tsx}"], Or If you have custom css class or third-party lib class then follow Safelisting with `install #fullhuman/postcss-purgecss first then try
// postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
...(process.env.NODE_ENV === 'production'
? {
'#fullhuman/postcss-purgecss': {
// added sections folder and changed extension to jsx
content: ['./src/components/**/*.jsx', './src/pages/**/*.js'],
defaultExtractor: content =>
content.match(/[\w-/:]+(?<!:)/g) || [],
},
}
: {}),
},
}`
Note: Each solution depend on it's context. I request to you read official docs carefully.

Material-UI have different style result in production mode?

I am writing a React app that uses server-side rendering. I am following the instruction here to set up a file.
Here is my .babelrc configuration file
{
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": { "version": 3, "proposals": true },
"targets": {
"browsers": "> 1%, not ie 11, not op_mini all",
"node": 13
}
}
],
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-proposal-class-properties",
"#babel/plugin-transform-runtime",
[
"import",
{
"libraryName": "#material-ui/icons",
"libraryDirectory": "utils", // default: lib
"camel2DashComponentName": false // default: true
},
"#material-ui/icons"
]
]
}
And this is webpack.config.js file
const path = require("path");
const nodeExternals = require("webpack-node-externals");
const commonConfig = {
devtool: "source-map",
module: {
rules: [{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }]
},
resolve: {
alias: {
"#material-ui/core": "#material-ui/core/es"
}
}
};
module.exports = [
{
...commonConfig,
entry: "./src/client",
output: {
path: path.resolve(__dirname, "public")
}
},
{
...commonConfig,
target: "node",
entry: "./src/server",
output: {
path: path.resolve(__dirname, "server")
},
externals: [nodeExternals()]
}
];
(Here is the full code in CodeSandBox and here is in Github if you want to try out)
The problem appear is when I bundle up the file, in development mode, everything work just fine. But when I try production mode, the CSS part starts to behave weirdly. When the file is first loaded from localhost, it is styled correctly (this happens in a very short time), then the style goes wrong as some styling is missing.
When I try to investigate, I find that all the style that is missing is the part I wrote with makeStyles(). All the built-in styles work just fine.
I tried to remove all the resolve property in webpack.config.js following this post, but it doesn't work. No matter what I try to change that property, nothing happens.
So now the only way I found that can make the app work in production build is to remove the code that removes the styling file (you can find that part at the end of client.js file), but I'm not sure what is the result of doing so.
So my questions are:
What can you suggest the fix for the app?
Why there is such a difference between two modes, development and production? I get that the production mode will include some minification, tree shaking, etc., and the development has most of that except for minification. So why there is a difference?
Edit: I found two possible and workable fixes for this bug: one is to stop removing those CSS files (code that I wrote in client.js file); the other one is to remove the nodeExternal() plugin in webpack.config.js and bundle everything for the server file. What do you think ?
I had a similar issue, although without server-side rendering. It was caused by a different order of stylesheets in dev and prod environments, causing unwanted overwrites. In dev env all stylesheets created by makeStyles() were injected after ALL MUI stylesheets, but in production they were mixed.
Solution:
Add an option: { index: 1 } to all makeStyles() invocations, in order to place those sheets after the MUI sheets which have an index of 0 (by default). This optional argument is passed directly to underlying JSS's jss.createStyleSheet() and dictates the injection order:
const useStyles = makeStyles(
(...), // styles
{ index: 1 }, // optional argument for JSS, to set position after MUI stylesheets
)
(after: https://stackoverflow.com/a/62646041/624597)

How can i optimize the size of my JS file After WebPack ? (VUEJS)

My JS file after WebPack is 6.53 Mb. The Application has 20 components and many features.
Do you think i can reduce the size ? Any Orientations ?
Thank you.
My JS file after WebPack is 6.53 Mb
You're question is not apparent but I am interpreting this as your project is in development mode.
Well, there are lot of optimizations you can do to reduce your bundle size using methods like gzip compression.
For vue, gzip compression can be achieved dynamically using the following code in vue.config.js:
const CompressionPlugin = require("compression-webpack-plugin")
let plugins = []
if (process.env.NODE_ENV === "production") {
const compressionTest = /\.(js|css|html|ico)(\?.*)?$/i
plugins = [
new CompressionPlugin({
algorithm: "gzip",
compressionOptions: {
numiterations: 15
},
minRatio: 0.99,
test: compressionTest
})
]
}
module.exports = {
productionSourceMap: false,
configureWebpack: {
plugins
}
}
Now, when you run yarn build, gzip files should be generated automatically.
Moreover, you can use PurgeCSS to remove unused css in your project. You could also use CSS Modules to shorten up your css class names.
Example configuration for css modules in vue.config.js would be:
module.exports = {
css: {
requireModuleExtension: true,
sourceMap: false,
loaderOptions: {
css: {
localsConvention: "camelCaseOnly",
modules: {
localIdentName:
process.env.NODE_ENV === "production"
? "[hash:base64:5]"
: "app-[hash:base64:5]-[local]"
}
}
}
}
}
Usage example: https://vue-loader.vuejs.org/guide/css-modules.html#usage
You could also use Functional Components where you think state is not necessary. Since, functional components doesn't handle any state, you should gain some optimizations. This is negligble in small projects but should help in big projects.
I hope this helps!

how can I remove unused code when I build my bundle?

I am not sure how to organize my js code.
Our front end is customized to different customers. Majority of the base code is common across all customers. However there are cases where certain functionality is overridden for each customer.
For example if we have 2 functions Function1 and Function2.
Customer1 uses Function1 while Customer2 uses Function2. How can I make sure that when I build the code for Customer, Function2 will not be included in the bundle? And when I build the code for Customer2, then Function1 will not be included int he bundle?
The other option I have, and that I am trying to avoid, is to have a separate code repo for each customer.
I think what you need is Tree-Shaking in webpack.
Tree shaking can be a stubborn process depending on how the library you are using in your application is developed.
If you find that you are using a module that does not shake dead code properly, you can always use the babel-plugin-import plugin. This plugin will build your bundle with only the code you import and nothing else. Here is an example of my babel 7.x config file. I use it to remove a lot of code that was not being tree-shaken by webpack from material-ui.
{
"presets": [
"#babel/preset-typescript",
"#babel/preset-react"
],
"plugins": [
[
"babel-plugin-import",
{
"libraryName": "#material-ui/core",
"libraryDirectory": "/",
"camel2DashComponentName": false
},
"core"
],
[
"babel-plugin-import",
{
"libraryName": "#material-ui/icons",
"libraryDirectory": "/",
"camel2DashComponentName": false
},
"icons"
]
]
}
When using this plugin in certain libraries, some of your imports also may break and you may need to import certain things on their own. I had to do this with material-ui's makeStyles function.
Feel free to remove what is unnecessary to you and keep the parts that help :).
At webpack configuration, optimization/usedExports: true will remove unused code.
webpack.config.js
module.exports = [
{
entry: "./main.js",
output: {
filename: "output.js"
},
optimization: {
usedExports: true, // <- remove unused function
}
},
{
entry: "./main.js",
output: {
filename: "without.js"
},
optimization: {
usedExports: false, // <- no remove unused function
}
}
];
lib.js
exports.usedFunction = () => {
return 0;
};
exports.unusedFunction = () =>{
return 1;
};
main.js
// Not working
// const lib = require("./lib");
// const usedFunction = lib.usedFunction;
// Working
const usedFunction = require("./lib").usedFunction;
usedFunction()
```shell
$ webpack
Generated Output file:
dist/output.js
(()=>{var r={451:(r,t)=>{t.W=()=>0}},t={};(0,function e(o){var n=t[o];if(void 0!==n)return n.exports;var p=t[o]={exports:{}};return r[o](p,p.exports,e),p.exports}(451).W)()})();
dist/without.js
(()=>{var n={451:(n,r)=>{r.usedFunction=()=>0,r.unusedFunction=()=>1}},r={};(0,function t(u){var e=r[u];if(void 0!==e)return e.exports;var o=r[u]={exports:{}};return n[u](o,o.exports,t),o.exports}(451).usedFunction)()})();
^^^^^^^^^^^

How can I transpile a dependency in node_modules with Nuxt 2?

I have read of issues with transpiling node_modules with Nuxt, but the new Nuxt 2 is said to have solved this with a transpile option in the nuxt.config.js file.
https://nuxtjs.org/api/configuration-build/#transpile
Here is what I have:
export default {
router: {
base: '/',
},
build: {
transpile: [
'choices.js',
'lazysizes',
'swiper',
'vee-validate'
],
extractCSS: true
},
srcDir: 'src/',
performance: {
gzip: true
},
render: {
compressor: {
threshold: 100
}
},
dev: false
}
I removed a few things that are unrelated to make it easier to read.
When I run npm run build (nuxt build) the compiled JS files contain references to es6 and es7 code such as const and let etc when it should be var.
I have isolated this issue to be coming from Swiper. It appears to internally depend on something called Dom7 that seems to be causing the problem.
I am wanting to compile these node_modules dependencies to es5 if possible. I'm not sure my current setup is actually doing anything at all in that regard.
I believe Nuxt uses vue-app for Babel, but I even tried the following to no success:
babel: {
presets: [
'#babel/preset-env'
],
plugins: [
'#babel/plugin-syntax-dynamic-import'
]
}
Not much joy there either. Nothing appears differently in the final build.
I am using Nuxt 2.1.0
Any help appreciated. Thanks!
You also need to transpile Dom7, so the Nuxt config should have:
build: {
transpile: [
'swiper',
'dom7',
],
}
I have the exact same issue.
The vendor option under build is deprecated, so it's simply ignored I believe from what I read here https://medium.com/nuxt/nuxt-2-is-coming-oh-yeah-212c1a9e1a67#a688
I managed to isolate my case to the "swiper" library. If I remove that from my project, all references to let, const or class are gone. I've tried the transpile option too, but it does not seem to have any effect.
Will you try to exclude swiper from your project to see if we can isolate the issue?

Categories

Resources