Add TailwindCSS to Phoenix with Brunch - sass

I'm having trouble figuring out how to add npm packages which are not specifically built to be used with brunch to my elixir/phoenix project.
One thing I don't want to do is manually copy files from node_modules/ to vendor/.
If anyone knows how to properly configure Brunch to use Tailwind in a Phoenix app, any help would be greatly appreciated.

For Phoenix 1.4 I've made a blog post about how you can setup it. https://equimper.com/blog/how-to-setup-tailwindcss-in-phoenix-1.4 This is using webpack and postcss
Create project mix phx.new myproject
Go in your assets cd assets
Add tailwind dependencies yarn add -D tailwindcss
Init tailwind theme ./node_modules/.bin/tailwind init
Add postcss dep yarn add -D postcss-loader
Create a file in /assets call postcss-config.js and add this code
module.exports = {
plugins: [require('tailwindcss')('./tailwind.js'), require('autoprefixer')],
}
Inside your webpack config change
use: [MiniCssExtractPlugin.loader, 'css-loader']
for
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
Finally add those tailwind stuff in your app.css file
#tailwind preflight;
#tailwind components;
#tailwind utilities;

Include postcss-brunch and tailwindcss packages
$ npm install postcss-brunch tailwindcss --save-dev
Create Tailwind config file (in assets directory)
$ ./node_modules/.bin/tailwindcss init
Add Tailwind as postcss plugin
assets/brunch-config.js
...
// Configure your plugins
plugins: {
babel: {
// Do not use ES6 compiler in vendor code
ignore: [/vendor/]
},
postcss: {
processors: [
require('tailwindcss')('./tailwind.js')
]
}
},
...
Use Tailwind in css
assets/css/app.css
#tailwind preflight;
#tailwind utilities;
https://tailwindcss.com/docs/installation

Related

Cache transformed node modules with vite/esbuild

vite build uses esbuild to transform both the package dependencies (node modules) as well as the app source code into the target JavaScript specification, i.e. es2015.
I observe that vite/esbuild re-transform the entire sources in ./node_modules every time vite build is run.
How can this build stack be used to keep and reuse the previously transformed files, at least for the entire ./node_modules folder (given dependencies didn't change of course) so that subsequent vite build command invocations run significantly faster?
One way to improve the performance of subsequent Vite build command invocations is by using a caching mechanism. You can use a caching tool such as cache-loader or hard-source-webpack-plugin to cache the transpilation results of the node modules.
This will allow Vite to reuse the previously transpiled files for the node modules, as long as the dependencies haven't changed.
This can greatly speed up the build process.
You can also try to configure esbuild to only transpile the changed files instead of the entire codebase using the -w or --watch option when running the esbuild command. This option tells esbuild to watch the input files and only transpile the files that have been modified.
In Vite, you can configure the esbuild plugin to use the --watch option by adding the following to your vite.config.js file:
const esbuildConfig = {
watch: true,
};
module.exports = {
esbuild: esbuildConfig,
};
Examples :
cache-loader:
Install the package:
npm install cache-loader --save-dev
In your vite.config.js file, configure the cache-loader to be used for transpiling the node modules by adding it as a rule in the build object:
module.exports = {
build: {
...
css: {
...
},
js: {
...
loaderOptions: {
cache: true,
cacheDirectory: 'node_modules/.cache'
}
},
...
}
}
Run your build command ( vite build )
hard-source-webpack-plugin:
install the package:
npm install hard-source-webpack-plugin --save-dev
In your vite.config.js file, import the plugin and add it to the build.plugins array:
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
build: {
...
plugins: [
new HardSourceWebpackPlugin()
],
...
}
}
Run your build command (vite build)
These examples, as you asked in your comment, are for Vite versions 2.5.8 and 3.x. However, in order to use them with Vite 3.x you need to update the build config to match the new format.
Please don't hesitate to write a comment if you still have a problem or questions!

Webpack failure after migrating to dart sass due to import "./App.scss" in App.tsx

I just tried to migrate from node-sass to dart sass (sass). The build fails while webpack (webpack --config webpack.config.js). Seems like it is not able to resolve Importing of scss. I have import "App scss" in App tsx
The updated webpack rule is
{
test: /.scss$/,
use: ["style-loader", "css-loader",
{
loader: "sass-loader",
options: {
// Prefer dart-sass
implementation: require("sass"),
}
}]
}
I am using rush as package manager. Below is the versions I have
sass: 1.53.0
sass-loader: 7.3.1
webpack#4.46.0
Any idea what is wrong in this ?

Why does compiling Font Awesome Sass to CSS create a fonts folder in the wrong location?

I'm compiling Font Awesome Sass files to CSS, and it's putting a fonts folder with all the font files at the root level of my project, which I don't want.
Specifically, I installed the free Font Awesome npm package as follows:
npm install --save-dev #fortawesome/fontawesome-free
I then added the following to a vendor.scss file:
$fa-font-path: '../../../../public/fonts' !default;
#import '~#fortawesome/fontawesome-free/scss/fontawesome';
#import '~#fortawesome/fontawesome-free/scss/brands';
#import '~#fortawesome/fontawesome-free/scss/regular';
#import '~#fortawesome/fontawesome-free/scss/solid';
This is the directory structure of the project:
(Project root)
|---fonts (I don't want this one.)
|---node_modules
| |---#fortawesome
| |---fontawesome-free
| |---scss
| |---_variables.scss (Contains original $fa-font-path being overridden.)
|---public
| |---css
| |---fonts (This is the one I want.)
|---src
|---sass
|---vendor.scss (Contains new $fa-font-path definition and FA Sass imports.)
If I change $fa-font-path to '../../../public/fonts' !default; or '../../public/fonts' !default; then the build process errors out and won't compile, but '../../../../public/fonts' !default; puts all the Font Awesome font files in a fonts folder at both the project root level and in the public/fonts folder. Why is it doing this, and more importantly, how can I stop it from creating the fonts folder at the root level? Thank you.
One thing I probably should have mentioned in my question is that I'm using the laravel-mix npm module to wrap around Webpack and bundle all my assets.
Laravel Mix returns a promise from its chained calls that allows you to call then on the end of it, from which I was able to write some custom code in the then callback to always remove the fonts directory at the project root level.
Specifically, my Mix file became the following:
const mix = require('laravel-mix');
const rimraf = require('rimraf');
mix.js('src/js/app.js', 'public/js/')
.extract(['vue'])
.sass('src/sass/vendor.scss', 'public/css/')
.sass('src/sass/app.scss', 'public/css/')
.then(() => {
rimraf.sync('fonts');
});
rimraf is an npm module that basically allows you to run rm -fr on a directory. The module can be gotten here: https://www.npmjs.com/package/rimraf

HTML + Laravel + npm + package.json workflow

I am wondering in how I should include my npm packages into my HTML. I have added "slidebars": "2.0.2" to my package.json. After that, I ran npm install. So far so good.
Now, I am new with both Laravel and npm. I am trying to use the "mix" feature provided in Laravel like this:
mix
.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css')
.version();
Does that automatically compile all the packages provided in the package.json into the single app.js + app.css? Or do I manually need to import the CSS + JS from the slidebars-plugin, like: <link href="/node_modules/slidebars/dist/slidebars.css" rel="stylesheet">?
For the css, the easiest way would to copy your css files to resources/assets/ and then link it to your app.scss like this:
#import "package.scss"
As for the JS, you can combine your vendor JS files into one and copy them to the public directory like this
mix.js([
'node_modules/package/dist/package.min.js',
'node_modules/package2/dist/package2.min.js',
'node_modules/package3/dist/package3.min.js',
], 'public/js/vendors.js');
Then in your view, you just include /js/vendors.js

Foundation with Laravel and Elixir

How should one use Foundation with Laravel?
I thought I'd install Foundation in vendor folder with bower install foundation. This results into having a vendor/bower_components folder where I have Foundation and all required libraries such as jQuery.
What should I add in gulpfile.js for Elixir to interpret this correctly? It should be possible to
update Bower components
install new Bower packages
modify Foundation Sass variables without these being overwritten when updating
use Compass
In a non-Laravel project I would run the Ruby gem foundation new my_project and include the compiled files manually. However, in this case the command creates a lot of files not required to work.
Laravel Elixir includes Libsass so you won't need Ruby to compile your Foundation Sass files from Laravel. All you'll need is bower and Laravel Elixir. Also you don't need to copy files from bower_components folder to resources/assets folder.
First follow official instrucctions for installing Elixir.
Then create the file .bowerrc in the root of your Laravel project with this content:
{
"directory": "vendor/bower_components"
}
Then create the file bower.json in the root of your Laravel project with this content:
{
"name": "laravel-and-foundation",
"private": "true",
"dependencies": {
"foundation": "latest"
}
}
Then install both bower and foundation:
npm install --global bower
bower install # This will install Foundation into vendor/bower_components
Then create the file resources/assets/sass/_settings.scss file with this content:
// Custom settings for Zurb Foundation. Default settings can be found at
// vendor/bower_components/foundation/scss/foundation/_settings.scss
Then edit the file resources/assets/sass/app.scss file with this content:
#import "normalize";
#import "settings";
// Include all foundation
#import "foundation";
// Or selectively include components
// #import
// "foundation/components/accordion",
// "foundation/components/alert-boxes",
// "foundation/components/block-grid",
// "foundation/components/breadcrumbs",
// "foundation/components/button-groups",
// "foundation/components/buttons",
// "foundation/components/clearing",
// "foundation/components/dropdown",
// "foundation/components/dropdown-buttons",
// "foundation/components/flex-video",
// "foundation/components/forms",
// "foundation/components/grid",
// "foundation/components/inline-lists",
// "foundation/components/joyride",
// "foundation/components/keystrokes",
// "foundation/components/labels",
// "foundation/components/magellan",
// "foundation/components/orbit",
// "foundation/components/pagination",
// "foundation/components/panels",
// "foundation/components/pricing-tables",
// "foundation/components/progress-bars",
// "foundation/components/reveal",
// "foundation/components/side-nav",
// "foundation/components/split-buttons",
// "foundation/components/sub-nav",
// "foundation/components/switches",
// "foundation/components/tables",
// "foundation/components/tabs",
// "foundation/components/thumbs",
// "foundation/components/tooltips",
// "foundation/components/top-bar",
// "foundation/components/type",
// "foundation/components/offcanvas",
// "foundation/components/visibility";
Configure the file gulpfile.js with this content:
elixir(function(mix) {
// Compile CSS
mix.sass(
'app.scss', // Source files
'public/css', // Destination folder
{includePaths: ['vendor/bower_components/foundation/scss']}
);
// Compile JavaScript
mix.scripts(
['vendor/modernizr.js', 'vendor/jquery.js', 'foundation.min.js'], // Source files. You can also selective choose only some components
'public/js/app.js', // Destination file
'vendor/bower_components/foundation/js/' // Source files base directory
);
});
To build just follow official docs:
gulp # Run all tasks...
gulp --production # Run all tasks and minify files
gulp watch # Watch for changes and run all tasks on the fly
Your compiled files will be at public/css/app.css and public/js/app.js.
To update to the latest Zurb Foundation version just run:
bower update
Copy Fundation > scss folder to resources > assets folder, rename scss to sass, in your gulpfile.js add following
elixir(function(mix) {
mix.sass('foundation.scss');
});
Run gulp which will generate foundation.css file in public > css folder, include that file in your project.
For js files you can simple use something like this to copy the file
mix.copy('resources/assets/foundation/js/app.js', 'public/js/app.js');

Resources