Browsersync keeps reloading - wordpress

I have Gulp + Browsersync working with Wordpress.
Everything was working well, reloading every time I change files.
But since yesterday only, Browsersync keeps reloading without any reason.
I didn't made any changes on my gulpfile. I tried reverting to a former commit from 2 days ago, same thing. I don't know where it comes from.
Here's my repo.
I tried :
downgrading browsersync to 2.24.4 from this post
adding this to gulp :
socket: {
clients: {
heartbeatTimeout: 60000
}
},
Here are my files.
gulpfile.babel.js
import { src, dest, watch, series, parallel } from 'gulp';
import yargs from 'yargs';
import sass from 'gulp-sass';
import cleanCss from 'gulp-clean-css';
import gulpif from 'gulp-if';
import postcss from 'gulp-postcss';
import sourcemaps from 'gulp-sourcemaps';
import autoprefixer from 'autoprefixer';
import imagemin from 'gulp-imagemin';
import del from 'del';
import webpack from 'webpack-stream';
import named from 'vinyl-named';
import browserSync from 'browser-sync';
import zip from 'gulp-zip';
import info from './package.json';
import replace from 'gulp-replace';
import wpPot from 'gulp-wp-pot';
import tailwindcss from 'tailwindcss';
// import purgeCss from 'gulp-purgecss';
const PRODUCTION = yargs.argv.prod;
export const clean = () => del(['dist']);
export const styles = () => {
return (
src('src/scss/app.scss')
.pipe(gulpif(!PRODUCTION, sourcemaps.init()))
.pipe(sass().on('error', sass.logError))
.pipe(postcss([tailwindcss('./tailwind.config.js')]))
.pipe(gulpif(PRODUCTION, postcss([autoprefixer])))
.pipe(gulpif(PRODUCTION, cleanCss({ compatibility: 'ie8' })))
// .pipe(
// gulpif(
// PRODUCTION,
// purgeCss({
// content: ['**/*.php']
// })
// )
// )
.pipe(gulpif(!PRODUCTION, sourcemaps.write()))
.pipe(dest('dist/css'))
.pipe(server.stream())
);
};
export const images = () => {
return src('src/images/**/*.{jpg,jpeg,png,svg,gif}')
.pipe(gulpif(PRODUCTION, imagemin()))
.pipe(dest('dist/images'));
};
export const copy = () => {
return src(['src/**/*', '!src/{images,js,scss}', '!src/{images,js,scss}/**/*']).pipe(
dest('dist')
);
};
export const watchForChanges = () => {
watch('src/scss/**/*.scss', styles);
watch('src/images/**/*.{jpg,jpeg,png,svg,gif}', series(images, reload));
watch(['src/**/*', '!src/{images,js,scss}', '!src/{images,js,scss}/**/*'], series(copy, reload));
watch('src/js/**/*.js', series(scripts, reload));
watch('**/*.php', reload);
};
export const scripts = () => {
return src(['src/js/bundle.js'])
.pipe(named())
.pipe(
webpack({
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
}
]
},
mode: PRODUCTION ? 'production' : 'development',
devtool: !PRODUCTION ? 'inline-source-map' : false,
output: {
filename: '[name].js'
}
})
)
.pipe(dest('dist/js'));
};
/***** Generating a POT file *****/
export const pot = () => {
return src('**/*.php')
.pipe(
wpPot({
domain: 'boosters',
package: info.name
})
)
.pipe(dest(`languages/${info.name}.pot`));
};
/***** Compress theme into a ZIP file after renaming _themename *****/
export const compress = () => {
return src([
'**/*',
'!node_modules{,/**}',
'!bundled{,/**}',
'!src{,/**}',
'!.babelrc',
'!.gitignore',
'!gulpfile.babel.js',
'!package.json',
'!package-lock.json'
])
.pipe(
gulpif(
// prevent bug if there are zip files inside the theme
file => file.relative.split('.').pop() !== 'zip',
replace('boosters', info.name)
)
)
.pipe(zip(`${info.name}.zip`))
.pipe(dest('bundled'));
};
/****** BrowserSync ******/
const server = browserSync.create();
export const serve = done => {
server.init({
proxy: 'localhost:8888/boosters', // put your local website link here
snippetOptions: {
ignorePaths: 'boosters/wp-admin/**'
},
ghostMode: false
// socket: {
// clients: {
// heartbeatTimeout: 60000
// }
// },
// logLevel: 'debug',
// logFileChanges: true,
// logConnections: true
});
done();
};
export const reload = done => {
server.reload();
done();
};
/****** Series & Parallel Scripts ******/
export const dev = series(clean, parallel(styles, images, scripts, copy), serve, watchForChanges);
export const build = series(clean, parallel(styles, images, scripts, copy), pot, compress);
export default dev;
package.json
{
"name": "boosters",
"version": "1.0.0",
"description": "A Wordpress website for Boost.rs by DoubleCat Studio",
"main": "gulpfile.babel.js",
"scripts": {
"start": "gulp",
"build": "gulp build --prod"
},
"repository": {
"type": "git",
"url": "git+ssh://git#github.com/indaviande/boosters.git"
},
"author": "Vianney Bernet",
"license": "ISC",
"bugs": {
"url": "https://github.com/indaviande/boosters/issues"
},
"browserslist": [
"last 4 version",
"> 1%",
"ie 11"
],
"homepage": "https://github.com/indaviande/boosters#readme",
"devDependencies": {
"#babel/core": "^7.4.3",
"#babel/preset-env": "^7.4.3",
"#babel/register": "^7.4.0",
"autoprefixer": "^9.5.1",
"babel-loader": "^8.0.5",
"browser-sync": "^2.26.7",
"del": "^4.1.0",
"gulp": "^4.0.0",
"gulp-clean-css": "^4.0.0",
"gulp-if": "^2.0.2",
"gulp-imagemin": "^5.0.3",
"gulp-postcss": "^8.0.0",
"gulp-replace": "^1.0.0",
"gulp-sass": "^4.0.2",
"gulp-sourcemaps": "^2.6.5",
"gulp-wp-pot": "^2.3.5",
"gulp-zip": "^4.2.0",
"tailwindcss": "^1.0.4",
"vinyl-named": "^1.1.0",
"webpack-stream": "^5.2.1",
"yargs": "^13.2.2"
},
"dependencies": {
"tar": ">4.4.7"
}
}

Browsersync has a log that you can inspect to see which files are being changed that trigger the reload. You can also increase specificity of what you're watching/ignoring. Start off small and gradually increase your glob paths until you can see reloads on all changes.
server.init({
logLevel: 'debug',
files: [
'wp-content/themes/**/*.css',
'wp-content/themes/**/*.js',
'wp-content/themes/**/*.php',
],
ignore: [
'folder-to-ignore/**/*.*'
]
});

Related

For my vue3, vuetify, ts project Vite builds dev, prod but in prod it does not release console

I created my first vue3, ts, vuetify project, using vite (4.1.1).
vite => server is fine, no error, no warning
vite build => no error, no warning, files are generated as expected in dist and work as expected.
But but, when I run build in console, it is stuck after generation, the process never ends. And without the process ending, I cannot deploy the solution :$.
Any idea of what could prevent it from finishing ?
tsconfig.json
{
"$schema": "https://json.schemastore.org/tsconfig.json",
"files": [],
"compilerOptions": {
"newLine": "lf"
},
"references": [
{ "path": "./tsconfig.config.json" },
{ "path": "./tsconfig.app.json" }
]
}
tsconfig.app.json
{
"$schema": "https://json.schemastore.org/tsconfig.json",
"extends": "#vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"#/*": ["./src/*"]
},
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["vuetify"]
}
}
tsconfig.app.json
{
"$schema": "https://json.schemastore.org/tsconfig.json",
"extends": "#vue/tsconfig/tsconfig.node.json",
"include": [
"vite.config.*"
],
"compilerOptions": {
"composite": true,
"types": ["node"]
}
}
vite.config.ts
import { defineConfig, type UserConfig } from 'vite';
import { visualizer } from 'rollup-plugin-visualizer';
import { checker } from 'vite-plugin-checker';
import vue from '#vitejs/plugin-vue';
import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify';
import { fileURLToPath, URL } from 'node:url';
import fs from 'node:fs';
/**
* Vite Configure
*
* #see {#link https://vitejs.dev/config/}
*/
export default defineConfig(async ({ command, mode }): Promise<UserConfig> => {
const config: UserConfig = {
// https://vitejs.dev/config/shared-options.html#base
base: './',
// https://vitejs.dev/config/shared-options.html#define
define: { 'process.env': {} },
plugins: [
// Vue3
vue({
template: {
// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin#image-loading
transformAssetUrls,
},
}),
// Vuetify Loader
// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin#vite-plugin-vuetify
vuetify({
autoImport: true,
styles: { configFile: 'src/styles/settings.scss' },
}),
// vite-plugin-checker
// https://github.com/fi3ework/vite-plugin-checker
checker({
typescript: true,
vueTsc: true,
eslint: {
lintCommand:
'eslint . --fix --cache --cache-location ./node_modules/.vite/vite-plugin-eslint', // for example, lint .ts & .tsx
},
}),
],
// https://vitejs.dev/config/server-options.html
server: {
fs: {
// Allow serving files from one level up to the project root
allow: ['..'],
},
},
// Resolver
resolve: {
// https://vitejs.dev/config/shared-options.html#resolve-alias
alias: {
'#': fileURLToPath(new URL('./src', import.meta.url)),
'~': fileURLToPath(new URL('./node_modules', import.meta.url)),
},
extensions: ['.js', '.json', '.jsx', '.mjs', '.ts', '.tsx', '.vue'],
},
// Build Options
// https://vitejs.dev/config/build-options.html
build: {
// Build Target
// https://vitejs.dev/config/build-options.html#build-target
target: 'esnext',
// Minify option
// https://vitejs.dev/config/build-options.html#build-minify
minify: 'esbuild',
// Rollup Options
// https://vitejs.dev/config/build-options.html#build-rollupoptions
rollupOptions: {
// #ts-ignore
output: {
manualChunks: {
// Split external library from transpiled code.
vue: ['vue', 'pinia'],
vuetify: [
'vuetify',
'vuetify/components',
'vuetify/directives'
],
materialdesignicons: ['#mdi/font/css/materialdesignicons.css'],
},
plugins: [
mode === 'analyze'
? // rollup-plugin-visualizer
// https://github.com/btd/rollup-plugin-visualizer
visualizer({
open: true,
filename: 'dist/stats.html',
})
: undefined,
],
},
},
},
esbuild: {
// Drop console when production build.
drop: command === 'serve' ? [] : ['console'],
},
};
// Write meta data.
fs.writeFileSync(
fileURLToPath(new URL('./src/Meta.ts', import.meta.url)),
`import type MetaInterface from '#/interfaces/MetaInterface';
// This file is auto-generated by the build system.
const meta: MetaInterface = {
version: '${require('./package.json').version}',
date: '${new Date().toISOString()}',
};
export default meta;
`
);
return config;
});
vite build --mode analyze : does build and opens the stat html so means the build is actually finished ? But still, it is stuck in console.
I checked circular dependencies.

Wp-strap Wordpress plugin boilerplate prod output is empty

I want to use this boilerplate https://github.com/wp-strap/wordpress-plugin-boilerplate to create Wordpress plugins .
The issue is yarn prod results in empty output (css files in public folder are empty) .
Yarn devis working fine.
Bellow are my config files :
package.json
{
"name": "wordpress-webpack-workflow",
"version": "1.1.4",
"author": "WP-Strap",
"license": "MIT",
"homepage": "https://github.com/wp-strap/wordpress-webpack-workflow",
"description": "Modern WebPack workflow for WordPress front-end development and testing (plugins & themes) with handy tools included.\n",
"main": "index.js",
"repository": {
"type": "git",
"url": "https://github.com/wp-strap/wordpress-webpack-workflow.git"
},
"bugs": {
"url": "https://github.com/wp-strap/wordpress-webpack-workflow/issues"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"prod": "webpack --env NODE_ENV=production --env production",
"prod:watch": "webpack --env NODE_ENV=production --env production --watch",
"dev": "webpack --env NODE_ENV=development",
"dev:watch": "webpack --env NODE_ENV=development --watch",
"eslint": "eslint assets/src/js/**/*.js",
"eslint:fix": "eslint assets/src/js/**/*.js --fix",
"stylelint": "stylelint assets/src/**/**/*.{css,scss,pcss}",
"stylelint:fix": "stylelint assets/src/**/**/*.{css,scss,pcss} --fix",
"prettier": "prettier assets/src/js/**/*.js",
"prettier:fix": "prettier --write assets/src/js/**/*.js",
"translate": "wp-pot --src '**/**/**/*.php' --dest-file 'languages/report-error.pot' --package 'report-error' --domain 'report-error' --last-translator 'WP SCRIPT LAB <wpscriptlab#gmail.com>' --team 'WP SCRIPT LAB <wpscriptlab#gmail.com>' --bug-report 'wpscriptlab.com'"
},
"babel": {
"extends": "./webpack/babel.config.js"
},
"eslintConfig": {
"extends": [
"./webpack/.eslintrc.js"
]
},
"prettier": "./webpack/.prettierrc.js",
"stylelint": {
"ignoreFiles": [
"./assets/public/css/**/*.css",
"./vendor/**/**/*.css",
"./node_modules/**/**/*.css",
"./tests/**/**/*.css"
],
"extends": [
"./webpack/.stylelintrc.js"
]
},
"dependencies": {},
"devDependencies": {
"#babel/core": "^7.12.10",
"#babel/eslint-parser": "^7.12.1",
"#babel/preset-env": "^7.12.11",
"#wordpress/eslint-plugin": "^7.4.0",
"autoprefixer": "^10.2.1",
"babel-loader": "^8.2.2",
"browser-sync": "^2.26.13",
"browser-sync-webpack-plugin": "^2.3.0",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^5.0.1",
"eslint": "^7.17.0",
"eslint-webpack-plugin": "^2.4.1",
"eslint-plugin-prettier": "^3.3.1",
"glob-all": "^3.2.1",
"image-minimizer-webpack-plugin": "^2.2.0",
"imagemin-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-optipng": "^8.0.0",
"imagemin-svgo": "^8.0.0",
"mini-css-extract-plugin": "^1.3.3",
"node-sass-magic-importer": "^5.3.2",
"postcss": "^8.2.4",
"postcss-advanced-variables": "^3.0.1",
"postcss-import": "^14.0.0",
"postcss-import-ext-glob": "^2.0.0",
"postcss-loader": "^4.1.0",
"postcss-nested": "^5.0.3",
"postcss-nested-ancestors": "^2.0.0",
"prettier": "^2.2.1",
"purgecss-webpack-plugin": "^3.1.3",
"sass": "^1.32.2",
"sass-loader": "^10.1.0",
"stylelint": "^13.8.0",
"stylelint-scss": "^3.18.0",
"stylelint-webpack-plugin": "^2.1.1",
"webpack": "^5.12.3",
"webpack-cli": "^4.3.1",
"webpackbar": "^5.0.0-3",
"wp-pot-cli": "^1.5.0"
},
"keywords": [
"wordpress",
"workflow",
"webpack",
"theme",
"plugin",
"WebPack",
"BrowserSync",
"PostCSS",
"Autoprefixer",
"PurgeCSS",
"BabelJS",
"Eslint",
"Stylelint",
"SCSS",
"WP-Pot"
]
}
composer.json
{
"name": "wpstrap/wordpress-plugin-boilerplate",
"description": "Wordpress Plugin Boilerplate",
"version": "0.3.1",
"minimum-stability": "stable",
"prefer-stable": true,
"type": "wordpress-plugin",
"license": "MIT",
"homepage": "https://wp-strap.com",
"autoload": {
"psr-4": {
"ReportError\\": "src/"
}
},
"scripts": {
"phpcs": "./vendor/bin/phpcs"
},
"require": {
"php": ">=7.1",
"micropackage/requirements": "^1.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.1",
"wp-coding-standards/wpcs": "*",
"automattic/phpcs-neutron-ruleset": "^3.3",
"phpcompatibility/phpcompatibility-wp": "^2.1"
},
"keywords": [
"wordpress",
"plugin",
"boilerplate",
"framework"
],
"authors": [
{
"name": "WP-Strap",
"email": "hello#wp-strap.com",
"homepage": "https://wp-strap.com"
}
],
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
webpack.config.js
/**
* This is a main entrypoint for Webpack config.
*
* #since 1.0.0
*/
const path = require( 'path' );
// Paths to find our files and provide BrowserSync functionality.
const projectPaths = {
projectDir: __dirname, // Current project directory absolute path.
projectJsPath: path.resolve( __dirname, 'assets/src/js' ),
projectScssPath: path.resolve( __dirname, 'assets/src/scss' ),
projectImagesPath: path.resolve( __dirname, 'assets/src/images' ),
projectOutput: path.resolve( __dirname, 'assets/public' ),
projectWebpack: path.resolve( __dirname, 'webpack' ),
};
// Files to bundle
const projectFiles = {
// BrowserSync settings
browserSync: {
enable: true, // enable or disable browserSync
host: 'localhost',
port: 3000,
mode: 'proxy', // proxy | server
server: { baseDir: [ 'public' ] }, // can be ignored if using proxy
proxy: 'report-error.local',
// BrowserSync will automatically watch for changes to any files connected to our entry,
// including both JS and Sass files. We can use this property to tell BrowserSync to watch
// for other types of files, in this case PHP files, in our project.
files: '**/**/**.php',
reload: true, // Set false to prevent BrowserSync from reloading and let Webpack Dev Server take care of this
// browse to http://localhost:3000/ during development,
},
// JS configurations for development and production
projectJs: {
eslint: true, // enable or disable eslint | this is only enabled in development env.
filename: 'js/[name].js',
entry: {
frontend: projectPaths.projectJsPath + '/frontend.js',
backend: projectPaths.projectJsPath + '/backend.js',
},
rules: {
test: /\.m?js$/,
}
},
// CSS configurations for development and production
projectCss: {
postCss: projectPaths.projectWebpack + '/postcss.config.js',
stylelint: true, // enable or disable stylelint | this is only enabled in development env.
filename: 'css/[name].css',
use: 'sass', // sass || postcss
// ^ If you want to change from Sass to PostCSS or PostCSS to Sass then you need to change the
// styling files which are being imported in "assets/src/js/frontend.js" and "assets/src/js/backend.js".
// So change "import '../sass/backend.scss'" to "import '../postcss/backend.pcss'" for example
rules: {
sass: {
test: /\.s[ac]ss$/i
},
postcss: {
test: /\.pcss$/i
}
},
purgeCss: { // PurgeCSS is only being activated in production environment
paths: [ // Specify content that should be analyzed by PurgeCSS
__dirname + '/assets/src/js/**/*',
__dirname + '/templates/**/**/*',
__dirname + '/template-parts/**/**/*',
__dirname + '/blocks/**/**/*',
__dirname + '/*.php',
]
}
},
// Source Maps configurations
projectSourceMaps: {
// Sourcemaps are nice for debugging but takes lots of time to compile,
// so we disable this by default and can be enabled when necessary
enable: true,
env: 'dev-prod', // dev | dev-prod | prod
// ^ Enabled only for development on default, use "prod" to enable only for production
// or "dev-prod" to enable it for both production and development
devtool: 'source-map' // type of sourcemap, see more info here: https://webpack.js.org/configuration/devtool/
// ^ If "source-map" is too slow, then use "cheap-source-map" which struck a good balance between build performance and debuggability.
},
// Images configurations for development and production
projectImages: {
rules: {
test: /\.(jpe?g|png|gif|svg)$/i,
},
// Optimization settings
minimizerOptions: {
// Lossless optimization with custom option
// Feel free to experiment with options for better result for you
// More info here: https://webpack.js.org/plugins/image-minimizer-webpack-plugin/
plugins: [
[ 'gifsicle', { interlaced: true } ],
[ 'jpegtran', { progressive: true } ],
[ 'optipng', { optimizationLevel: 5 } ],
[ 'svgo', {
plugins: [
{ removeViewBox: false, },
],
}, ],
],
}
}
}
// Merging the projectFiles & projectPaths objects
const projectOptions = {
...projectPaths, ...projectFiles,
projectConfig: {
// add extra options here
}
}
// Get the development or production setup based
// on the script from package.json
module.exports = env => {
if ( env.NODE_ENV === 'production' ) {
return require( './webpack/config.production' )( projectOptions );
} else {
return require( './webpack/config.development' )( projectOptions );
}
};
config.base.js
/**
* This holds the configuration that is being used for both development and production.
* This is being imported and extended in the config.development.js and config.production.js files
*
* #since 1.1.0
*/
const magicImporter = require( 'node-sass-magic-importer' ); // Add magic import functionalities to SASS
const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' ); // Extracts the CSS files into public/css
const BrowserSyncPlugin = require( 'browser-sync-webpack-plugin' ) // Synchronising URLs, interactions and code changes across devices
const WebpackBar = require( 'webpackbar' ); // Display elegant progress bar while building or watch
const ImageMinimizerPlugin = require( 'image-minimizer-webpack-plugin' ); // To optimize (compress) all images using
const CopyPlugin = require( "copy-webpack-plugin" ); // For WordPress we need to copy images from src to public to optimize them
module.exports = ( projectOptions ) => {
/**
* CSS Rules
*/
const cssRules = {
test: projectOptions.projectCss.use === 'sass' ? projectOptions.projectCss.rules.sass.test : projectOptions.projectCss.rules.postcss.test,
exclude: /(node_modules|bower_components|vendor)/,
use: [
MiniCssExtractPlugin.loader, // Creates `style` nodes from JS strings
"css-loader", // Translates CSS into CommonJS
{ // loads the PostCSS loader
loader: "postcss-loader",
options: require( projectOptions.projectCss.postCss )( projectOptions )
}
],
};
if ( projectOptions.projectCss.use === 'sass' ) { // if chosen Sass then we're going to add the Sass loader
cssRules.use.push( { // Compiles Sass to CSS
loader: 'sass-loader',
options: {
sassOptions: { importer: magicImporter() } // add magic import functionalities to sass
}
} );
}
/**
* JavaScript rules
*/
const jsRules = {
test: projectOptions.projectJs.rules.test,
include: projectOptions.projectJsPath,
exclude: /(node_modules|bower_components|vendor)/,
use: 'babel-loader' // Configurations in "webpack/babel.config.js"
};
/**
* Images rules
*/
const imageRules = {
test: projectOptions.projectImages.rules.test,
use: [
{
loader: 'file-loader',// Or `url-loader` or your other loader
},
],
}
/**
* Optimization rules
*/
const optimizations = {};
/**
* Plugins
*/
const plugins = [
new WebpackBar( // Adds loading bar during builds
// Uncomment this to enable profiler https://github.com/nuxt-contrib/webpackbar#options
// { reporters: [ 'profile' ], profile: true }
),
new MiniCssExtractPlugin( { // Extracts CSS files
filename: projectOptions.projectCss.filename
} ),
new CopyPlugin( { // Copies images from src to public
patterns: [ { from: projectOptions.projectImagesPath, to: projectOptions.projectOutput + '/images' }, ],
} ),
new ImageMinimizerPlugin( { // Optimizes images
minimizerOptions: projectOptions.projectImages.minimizerOptions,
} ),
];
// Add browserSync to plugins if enabled
if ( projectOptions.browserSync.enable === true ) {
const browserSyncOptions = {
files: projectOptions.browserSync.files,
host: projectOptions.browserSync.host,
port: projectOptions.browserSync.port,
}
if ( projectOptions.browserSync.mode === 'server' ) {
Object.assign( browserSyncOptions, { server: projectOptions.browserSync.server } )
} else {
Object.assign( browserSyncOptions, { proxy: projectOptions.browserSync.proxy } )
}
plugins.push( new BrowserSyncPlugin( browserSyncOptions, { reload: projectOptions.browserSync.reload } ) )
}
return {
cssRules: cssRules, jsRules: jsRules, imageRules: imageRules, optimizations: optimizations, plugins: plugins
}
}
config.production.js
/**
* Webpack configurations for the production environment
* based on the script from package.json
* Run with: "npm run prod" or or "npm run prod:watch"
*
* #since 1.0.0
*/
const glob = require( 'glob-all' );
const PurgecssPlugin = require( 'purgecss-webpack-plugin' ) // A tool to remove unused CSS
module.exports = ( projectOptions ) => {
process.env.NODE_ENV = 'production'; // Set environment level to 'production'
/**
* The base skeleton
*/
const Base = require( './config.base' )( projectOptions );
/**
* CSS rules
*/
const cssRules = {
...Base.cssRules, ...{
// add CSS rules for production here
}
};
/**
* JS rules
*/
const jsRules = {
...Base.jsRules, ...{
// add JS rules for production here
}
};
/**
* Image rules
*/
const imageRules = {
...Base.imageRules, ...{
// add image rules for production here
}
}
/**
* Optimizations rules
*/
const optimizations = {
...Base.optimizations, ...{
splitChunks: {
cacheGroups: {
styles: { // Configured for PurgeCSS
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
}
}
}
// add optimizations rules for production here
}
}
/**
* Plugins
*/
const plugins = [
...Base.plugins, ...[
new PurgecssPlugin( { // Scans files and removes unused CSS
paths: glob.sync( projectOptions.projectCss.purgeCss.paths, { nodir: true } ),
} ),
// add plugins for production here
]
]
/**
* Add sourcemap for production if enabled
*/
const sourceMap = { devtool: false };
if ( projectOptions.projectSourceMaps.enable === true && (
projectOptions.projectSourceMaps.env === 'prod' || projectOptions.projectSourceMaps.env === 'dev-prod'
) ) {
sourceMap.devtool = projectOptions.projectSourceMaps.devtool;
}
/**
* The configuration that's being returned to Webpack
*/
return {
mode: 'production',
entry: projectOptions.projectJs.entry, // Define the starting point of the application.
output: {
path: projectOptions.projectOutput,
filename: projectOptions.projectJs.filename
},
devtool: sourceMap.devtool,
optimization: optimizations,
module: { rules: [ cssRules, jsRules, imageRules ], },
plugins: plugins,
}
}
After some playing around i found that the empty output was caused by Purge CSS - purgecss-webpack-plugin. It removes unused css.
So the issue was that even though i added scss code in source files, it wasn't used anywhere in php files source folder.
So if i want to output the following css code :
.body {
color: red;
}
I need to add that class in php templates inside the src folder for plugin structure.
Results in successful output of css after yarn prod command :

issue loading css module classes in storybook v6.4

I'm having trouble getting storybook to play nice with css modules within my Gatsby project. I'm able to render the button component but it does not add any of my styling. On inspection of the element, I'm only getting undefined undefined from the following code.
button.jsx
import React from "react"
import * as css from "./style.module.css"
const Button = ({ variant = "button", type, value = null }) => {
const baseOfVariant = () => {
if (variant === "input") {
return (
<input
type={type}
value={value}
className={`${css.button} ${css.clear_button}`}
/>
)
}
return (
<button type={type} className={`${css.button} ${css.submit_button}`}>
{value}
</button>
)
}
return baseOfVariant()
}
export default Button
button.stories.jsx
import React from "react"
import Button from "./button"
export default {
title: "Button",
component: Button,
}
export const Template = args => <Button {...args} />
export const ButtonRegular = Template.bind({})
ButtonRegular.args = {
variant: "button",
value: "Click Me",
type: "submit",
}
main.js
module.exports = {
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.#(js|jsx|ts|tsx)"],
addons: ["#storybook/addon-links", "#storybook/addon-essentials"],
core: {
builder: "webpack5",
},
}
Storybook stuff in my devDeps
"devDependencies": {
"#babel/core": "^7.14.6",
"#babel/polyfill": "^7.12.1",
"#storybook/addon-actions": "^6.4.0-alpha.2",
"#storybook/addon-essentials": "^6.4.0-alpha.2",
"#storybook/addon-links": "^6.4.0-alpha.2",
"#storybook/addon-viewport": "^6.4.0-alpha.2",
"#storybook/builder-webpack5": "^6.4.0-alpha.2",
"#storybook/manager-webpack5": "^6.4.0-alpha.2",
"#storybook/react": "^6.4.0-alpha.2",
"babel-loader": "^8.2.2",
"prettier": "2.2.1",
"resize-observer-polyfill": "^1.5.1"
}
Gatsby needs to import css modules with the following synthax:
import * as css from "./style.module.css"
Where Storybook recognizes only this synthax:
import css from "./style.module.css"
This is due to the fact that Gatsby and Storybook don't use the same import convention. Fortunately, you can configure Storybook css module import mechanism via .storybook/main.js file.
const path = require("path")
module.exports = {
// You will want to change this to wherever your Stories will live
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.#(js|jsx|ts|tsx)"],
addons: ["#storybook/addon-links", "#storybook/addon-essentials"],
core: {
builder: "webpack5",
},
webpackFinal: async config => {
// Prevent webpack from using Storybook CSS rules to process CSS modules
config.module.rules.find(
rule => rule.test.toString() === "/\\.css$/"
).exclude = /\.module\.css$/
// Tell webpack what to do with CSS modules
config.module.rules.push({
test: /\.module\.css$/,
include: path.resolve(__dirname, "../src"),
use: [
{
loader: "style-loader",
options: {
modules: {
namedExport: true,
},
},
},
{
loader: "css-loader",
options: {
importLoaders: 1,
modules: {
namedExport: true,
},
},
},
],
})
// Transpile Gatsby module because Gatsby includes un-transpiled ES6 code.
config.module.rules[0].exclude = [/node_modules\/(?!(gatsby)\/)/]
// use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
config.module.rules[0].use[0].options.plugins.push(
require.resolve("babel-plugin-remove-graphql-queries")
)
return config
},
}
With the above configuration, Storybook now accept this import synthax and button.jsx is correctly styled.
import * as css from "./style.module.css"
If any one is looking for sass/scss related fix
import * as style from "./style.module.scss"
Where Storybook recognizes only this synthax:
your .storybook/main.js file.
const path = require("path");
module.exports = {
stories: ["../src/**/*.stories.{js,mdx}"],
addons: [
"#storybook/addon-docs",
"#storybook/addon-actions",
"#storybook/addon-controls",
"#storybook/addon-a11y",
"#storybook/addon-viewport",
],
// https://gist.github.com/shilman/8856ea1786dcd247139b47b270912324
core: {
builder: "webpack5",
},
webpackFinal: async config => {
// https://www.gatsbyjs.com/docs/how-to/testing/visual-testing-with-storybook/
config.module.rules.push({
test: /\.(js)$/,
use: [
{
loader: require.resolve("babel-loader"),
options: {
presets: [
// use #babel/preset-react for JSX and env (instead of staged presets)
require.resolve("#babel/preset-react"),
require.resolve("#babel/preset-env"),
],
plugins: [
// use #babel/plugin-proposal-class-properties for class arrow functions
require.resolve("#babel/plugin-proposal-class-properties"),
// use babel-plugin-remove-graphql-queries to remove static queries from components when rendering in storybook
require.resolve("babel-plugin-remove-graphql-queries"),
// use babel-plugin-react-docgen to ensure PropTables still appear
require.resolve("babel-plugin-react-docgen"),
],
},
},
],
exclude: [/node_modules\/(?!(gatsby)\/)/],
});
config.module.rules.push({
test: /\.s[ac]ss$/i,
oneOf: [
// module.scss files (e.g component styles.module.scss)
// https://webpack.js.org/loaders/style-loader/#modules
{
test: /\.module\.s?css$/,
use: [
// Add exports of a module as style to DOM
{
loader: "style-loader",
options: {
esModule: true,
modules: {
namedExport: true,
},
},
},
// Loads CSS file with resolved imports and returns CSS code
{
loader: "css-loader",
options: {
esModule: true,
modules: {
namedExport: true,
},
},
},
// Loads and compiles a SASS/SCSS file
{
loader: "sass-loader",
// only if you are using additional global variable
options: {
additionalData: "#import 'src/styles/global.scss';",
sassOptions: {
includePaths: ["src/styles"],
},
},
},
],
},
// scss files that are not modules (e.g. custom.scss)
{
use: [
// Add exports of a module as style to DOM
"style-loader",
// Loads CSS file with resolved imports and returns CSS code
"css-loader",
// Loads and compiles a SASS/SCSS file
{
loader: "sass-loader",
// only if you are using additional global variable
options: {
additionalData: "#import 'src/styles/global.scss';",
sassOptions: {
includePaths: ["src/styles"],
},
},
},
],
},
],
});
return config;
},
};
With the above configuration, Storybook now accept this import synthax and button.jsx is correctly styled.
import * as styles from "./style.module.scss"

Vuetify CSS missing when i build for production

We purchased a web app written in Vue from someone and we developing to change/improve it. One thing we added was Vuetify so we can use the Vuetify elements and everything has been working great while in development mode, but when we build for production the CSS for Vuetify elements is missing.
I have searched for this online already and have already tried what everybody is suggesting without any luck.
Anybody has an idea of what could be wrong and why npm run build would be missing some of the CSS?
What's weird is that all the UI functionality for Vue elements is working perfectly, just the CSS is missing.
Please see code samples below.
main.js:
import '#fortawesome/fontawesome-free/css/all.css'
import Vue from "vue";
import App from "./App.vue";
import VueMoment from "vue-moment";
import VueAnalytics from "vue-analytics";
import VueMeta from "vue-meta";
import { library } from "#fortawesome/fontawesome-svg-core";
import {
faCoffee,
faPlusCircle,
faChartLine,
faChevronDown,
faMobile,
faEnvelope,
faClock,
faUsers,
faPaperPlane,
faCheckCircle,
faCheck,
faLeaf,
} from "#fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "#fortawesome/vue-fontawesome";
import axios from "axios";
import router from "./router";
import store from "./store";
import vuetify from './plugins/vuetify';
import Vuetify from 'vuetify/lib'
library.add([
faCoffee,
faPlusCircle,
faChartLine,
faChevronDown,
faMobile,
faEnvelope,
faClock,
faUsers,
faPaperPlane,
faCheckCircle,
faCheck,
faLeaf,
]);
Vue.use(VueAnalytics, {
id: "xxx",
router,
});
Vue.use(VueMoment);
Vue.use(VueMeta);
Vue.component("font-awesome-icon", FontAwesomeIcon);
Vue.use(Vuetify)
axios.interceptors.response.use(undefined, async function (error) {
if (error.response.status === 401) {
await store.dispatch("auth/logout");
router.push("/login");
}
return Promise.reject(error);
});
// Plugins
// ...
// Sass file
require("./assets/styles/main.css");
Vue.config.productionTip = false;
new Vue({
router,
store,
vuetify,
render: (h) => h(App)
}).$mount("#app");
App.vue:
<template>
<v-app>
<v-main>
<router-view/>
</v-main>
</v-app>
</template>
<style>
.text-white {
color: #fff !important;
}
.text-gray-600 {
color: #757575 !important;
}
.font-semibold, .text-gray-700 {
color: #616161 !important;
}
</style>
package.json:
{
"name": "reviewgrower-spa",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"deploy": "git push dokku master"
},
"dependencies": {
"#fortawesome/fontawesome-svg-core": "^1.2.25",
"#fortawesome/free-solid-svg-icons": "^5.11.2",
"#fortawesome/vue-fontawesome": "^0.1.8",
"#fullhuman/postcss-purgecss": "^1.3.0",
"axios": "^0.19.0",
"chart.js": "^2.9.4",
"core-js": "^2.6.10",
"i": "^0.3.6",
"jquery": "^3.5.1",
"npm": "^6.13.0",
"tailwindcss-spinner": "^0.2.0",
"tailwindcss-toggle": "github:TowelSoftware/tailwindcss-toggle",
"url-parse": "^1.4.7",
"vue": "^2.6.10",
"vue-analytics": "^5.17.2",
"vue-chartjs": "^3.5.1",
"vue-click-outside": "^1.0.7",
"vue-clickaway": "^2.2.2",
"vue-feather-icons": "^4.22.0",
"vue-js-toggle-button": "^1.3.3",
"vue-meta": "^1.6.0",
"vue-moment": "^4.0.0",
"vue-router": "^3.1.3",
"vue-stripe-elements-plus": "^0.2.10",
"vuetify": "^2.4.0",
"vuex": "^3.0.1",
"vuex-persist": "^2.1.1"
},
"devDependencies": {
"#fortawesome/fontawesome-free": "^5.15.2",
"#vue/cli-plugin-babel": "^3.12.1",
"#vue/cli-plugin-eslint": "^3.12.1",
"#vue/cli-service": "^3.12.1",
"babel-eslint": "^10.0.3",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.2.3",
"sass": "^1.32.0",
"sass-loader": "^7.1.0",
"tailwindcss": "^1.1.3",
"vue-cli-plugin-vuetify": "~2.1.0",
"vue-template-compiler": "^2.5.21",
"vuetify-loader": "^1.7.0"
}
}
It's a little tough to understand what is missing where. If you think that is just missing then please try adding css onto the HTML file from the cdn and check the working.
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
I see that you are using webpack to compile the code. So, this could be also something related to webpack configuration. In your webpack rules do you have rules for css and scss. Because vuetify files are in scss.
My webpack configuration is as below when I do these type of circus.
--webpack.config.js--
const path = require("path");
const VuetifyLoaderPlugin = require("vuetify-loader/lib/plugin");
const { VueLoaderPlugin } = require("vue-loader");
module.exports = {
watch: true,
entry: {
main: 'main.js'
},
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.vue$/,
use: "vue-loader",
},
{
test: /\.s(c|a)ss$/,
use: [
"vue-style-loader",
"css-loader",
{
loader: "sass-loader",
// Requires sass-loader#^8.0.0
// options: {
// implementation: require('sass'),
// sassOptions: {
// fiber: require('fibers'),
// indentedSyntax: true // optional
// },
// },
},
],
},
],
},
plugins: [
new VueLoaderPlugin(),
new VuetifyLoaderPlugin({
/**
* This function will be called for every tag used in each vue component
* It should return an array, the first element will be inserted into the
* components array, the second should be a corresponding import
*
* originalTag - the tag as it was originally used in the template
* kebabTag - the tag normalised to kebab-case
* camelTag - the tag normalised to PascalCase
* path - a relative path to the current .vue file
* component - a parsed representation of the current component
*/
match(originalTag, { kebabTag, camelTag, path, component }) {
if (kebabTag.startsWith("core-")) {
return [
camelTag,
`import ${camelTag} from '#/components/core/${camelTag.substring(
4
)}.vue'`,
];
}
},
}),
],
}
Check your postcss.config.js, see if it has something to do with the purgecss.
You have to config the whitelist to ignore the vuetify styles.
Here is a sample for your reference:
const autoprefixer = require("autoprefixer");
const postcssImport = require("postcss-import");
const purgecss = require("#fullhuman/postcss-purgecss");
const IS_PROD = ["production", "prod"].includes(process.env.NODE_ENV);
let plugins = [];
if (IS_PROD) {
plugins.push(postcssImport);
plugins.push(
purgecss({
content: [
"./src/**/*.vue",
"./public/**/*.html",
`./node_modules/vuetify/src/**/*.ts`,
`./node_modules/vuetify/dist/vuetify.css`
],
defaultExtractor (content) {
const contentWithoutStyleBlocks = content.replace(/<style[^]+?<\/style>/gi, '')
return contentWithoutStyleBlocks.match(/[A-Za-z0-9-_/:]*[A-Za-z0-9-_/]+/g) || []
},
safelist: [ /-(leave|enter|appear)(|-(to|from|active))$/, /^(?!(|.*?:)cursor-move).+-move$/, /^router-link(|-exact)-active$/, /data-v-.*/ ],
whitelist: [
'container',
'row',
'spacer',
'aos-animate',
'col',
'[type=button]',
'v-application p',
],
whitelistPatterns: [
/^v-.*/,
/^col-.*/,
/^theme-.*/,
/^rounded-.*/,
/^data-aos-.*/,
/^(red|grey)--text$/,
/^text--darken-[1-4]$/,
/^text--lighten-[1-4]$/
],
whitelistPatternsChildren: [
/^post-content/,
/^v-input/,
/^swiper-.*/,
/^pswp.*/,
/^v-text-field.*/,
/^v-progress-linear/
]
})
);
}
module.exports = {
plugins:[
require('cssnano')({
preset: 'default'
}),
require('postcss-pxtorem')({
remUnit:15, //每个rem对应的px值
threeVersion:true
}),
...plugins,autoprefixer
]
}``
You are simply missing an include in your main.js (see vuetify docs):
import 'vuetify/dist/vuetify.min.css'
This will ensure that webpack includes the vuetify styles in the bundled CSS for production. This fixed the same issue for me (i.e. it worked locally but not in production).

dotenv values not loaded in nextjs

I am struggling to load my .env file in my NextJS app. Here is my code:
My .env is in root /
My index.js is in /pages/index.js
Here is my index.js:
require("dotenv").config({ path: __dirname + '/../.env' })
import React, {Component} from 'react'
import Layout from '../components/layout'
import axios from 'axios'
class Import extends Component{
uploadCSV = (evt) => {
evt.preventDefault();
const uploadURL = process.env.MY_UPLOAD_URL
let data = new FormData(evt.target)
axios.post(uploadURL, data, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then((res) => {
console.log(res)
})
}
render() {
return (
<div>
<Layout title="Import Chatbot Intents" description="Import Chatbot Intents">
<form onSubmit={this.uploadCSV} name="import_csv" className="import_csv">
<h2>Import CSV</h2>
<div className="form-group">
<label htmlFor="csv_file">Upload file here: </label>
<input type="file" name="csv_file" id="csv_file" ref="csv_file" />
</div>
<div className="form-group">
<input type="hidden" id="customer_id" name="customer_id" ref="customer_id" value="1"/>
<button className="btn btn-success">Submit</button>
</div>
</form>
</Layout>
</div>
)
}
}
export default Import
I observe that I can print out .env content in render() function, but I cannot do that in uploadCSV function.
For your info:
using just require("dotenv").config() doesn't work
using require("dotenv").config({path: "../"}) doesn't work
Updated
My env-config.js:
module.exports = {
'CSV_UPLOAD_URL': "http://localhost:3000/uploadcsv"
}
My babel.config.js:
const env = require('./env-config')
console.log(env)
module.exports = function(api){
// console.log({"process": process.env})
api.cache(false)
const presets = [
"next/babel",
"#zeit/next-typescript/babel"
]
const plugins = [
"#babel/plugin-transform-runtime",
[
'transform-define',
env
]
]
return { presets, plugins }
}
My package.json
{
"name": "Botadmin",
"scripts": {
"dev": "next -p 3001",
"build": "next build",
"start": "next start"
},
"dependencies": {
"#babel/runtime": "^7.1.5",
"#zeit/next-less": "^1.0.1",
"#zeit/next-typescript": "^1.1.1",
"#zeit/next-workers": "^1.0.0",
"axios": "^0.18.0",
"forever": "^0.15.3",
"less": "^3.8.1",
"multer": "^1.4.1",
"next": "7.0.2",
"nprogress": "^0.2.0",
"papaparse": "^4.6.2",
"react": "16.6.3",
"react-dom": "16.6.3",
"typescript": "^3.1.6",
"worker-loader": "^2.0.0"
},
"devDependencies": {
"#babel/plugin-transform-runtime": "^7.1.0",
"babel-plugin-transform-define": "^1.3.0",
"dotenv": "^6.1.0",
"fork-ts-checker-webpack-plugin": "^0.4.15"
}
}
The Error:
Module build failed (from ./node_modules/next/dist/build/webpack/loaders/next-babel-loader.js):
TypeError: Property property of MemberExpression expected node to be of a type ["Identifier","PrivateName"] but instead got "StringLiteral"
If you want to use env in Nextjs
Install babel-plugin-transform-define
create the env-config.js file and define your variables
const prod = process.env.NODE_ENV === 'production'
module.exports = {
'process.env.BACKEND_URL': prod ? 'https://api.example.com' : 'https://localhost:8080'
}
Create the .babelrc.js file
const env = require('./env-config.js')
module.exports = {
presets: ['next/babel'],
plugins: [['transform-define', env]]
}
Now you have access to the env in your code
process.env.BACKEND_URL
Alternatives: next-env
As of Next.js 9.4, there is a built-in solution for setting environment variables https://nextjs.org/docs/basic-features/environment-variables
Thanks for #Alex for the answer. Another way to solve the same problem is to install dotenv-webpack using npm install -D dotenv-webpack.
Once installed. edit next.config.js:
require('dotenv').config()
const Dotenv = require('dotenv-webpack')
const path = require('path')
const withTypescript = require('#zeit/next-typescript')
const withWorkers = require('#zeit/next-workers')
const withLess = require('#zeit/next-less')
module.exports = withWorkers(withLess(withTypescript({
context: __dirname,
generateEtags: false,
entry: './pages/index.js',
distDir: 'build',
pageExtensions: ['js', 'jsx', 'ts', 'tsx'],
cssModules: false,
webpack: (config, options) => {
config.plugins = config.plugins || []
config.plugins = [
...config.plugins,
// Read the .env file
new Dotenv({
path: path.join(__dirname, '.env'),
systemvars: true
})
]
// Fixes npm packages that depend on `fs` module
config.node = {
fs: 'empty'
}
return config
}
})))
I know I'm a bit late, but, you can just install dotenv and use it inside of your next.config.js file
require("dotenv").config();
const environment = process.env.NODE_ENV || "dev";
if you need to replicate next.js env loading in other files (setupTests.ts, next-logger.config.js) do this:
const { loadEnvConfig } = require('#next/env')
loadEnvConfig(__dirname, true, {
info: () => null,
error: console.error,
})

Resources