I'm working on a project that has two separate js folders for user (public/js) and admin usage (public/admin_stuff/js).
I'm going to have two all.js files , one for user section js files and another for admin section js files . how can i achieve that in a neat way?
If you are using elixir, then:
// For admin
mix.scripts([
'admin_js_source_folder/**/*.js',
], 'public/admin_stuff/js/all.js');
// Another
mix.scripts([
'other_folder_js_files/**/*.js',
], 'public/other/js/all.js');
Other cases:
gulp.task('admin', function() {
return gulp.src('admin_stuff/js/**/*.js')
.pipe(concat('all.js'))
.pipe(gulp.dest('public/admin'));
})
gulp.task('other', function() {
return gulp.src('other/js/**/*.js')
.pipe(concat('all.js'))
.pipe(gulp.dest('public/other'));
})
gulp.task('default', ['admin', 'other']);
If your are using laravel 5, i recommend using elixir:
https://laravel.com/docs/5.0/elixir
Related
I am building a project using Laravel/Inertia/Vue and I am using Tailwind CSS.
I want to have separate admin.css and client.css files using tailwindcss 3.2 ability to have multiple config files:
./styles/admin.css
#config "./tailwind.admin.config.js"
#tailwind base;
#tailwind components;
#tailwind utilities;
but the problem is that Vite will build just app.css for me not the admin one
vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '#vitejs/plugin-vue';
export default defineConfig({
plugins: [
laravel({
input: 'resources/js/app.js',
ssr: 'resources/js/ssr.js',
refresh: true,
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
],
ssr: {
noExternal: ['#inertiajs/server'],
},
server: {
host: "localhost",
},
});
app.css is imported in app.js
I can not figure it out
Could you please help me?
I want to have separate admin.css and client.css files per each tailwindcss config file.
You can pass an array of input files to vite as follows:
input: ['resources/js/app.js','resources/css/admin.css','resources/css/client.css']
This should result in seperate output files in your build directory.
If you want to keep the css as javascript import you can create a second InertiaApp for the admin area:
Copy app.js and rename it like 'admin.js'
Change css import in admin.js to '/styles/admin.css'
Change your vite input to: input: ['resources/js/app.js','resources/js/admin.js']
Use a different blade layouts for the 'admin' area with reference to admin.js instead of app.js : #vite('resources/js/admin.js')
Thanks #dustin for your answer. Here are some more things:
I can split javascript application by defining multiple rootViews using inertia-laravel#0.3.2 in HandleInertiaRequests.php middleware:
public function rootView(Request $request)
{
if ($request->routeIs('admin.*')) {
return 'admin';
}
return 'app';
}
And have two different apps.
But do you think its a good approach to have two different apps?
I like the separation idea but is it the right way?
I Also have concerns about bundling and mixing in inertia and ssr, would it be a problem for that when you have two apps? I dont know anything about inertia's way of working
I was hoping there is some other method like creating a higher order component or something like that. I am very new to Vue world and I am still trying to learn.
I am using the StoryShots addon for Storybook to test snapshots from my React project. I would like to save all snapshot files in one directory in relation to the project directory. The default is that the snapshots are saved in relation to the story's location. I tried various configurations (like working with __dirname) but couldn't come up with a solution yet. Maybe someone has an idea?
Here is my storyshots test file used by Jest (storyshots.test.ts):
import initStoryshots, { multiSnapshotWithOptions, Stories2SnapsConverter } from '#storybook/addon-storyshots'
initStoryshots({
test: multiSnapshotWithOptions(),
stories2snapsConverter: new Stories2SnapsConverter({
snapshotsDirName: './__snapshots__/',
storiesExtensions: ['.js', '.jsx', '.ts', '.tsx'],
})
})
You can do something like this:
const IMAGE_SNAPSHOT_DIR = path.resolve(path.join(__dirname, 'component-image-snapshots'));
initStoryshots({
test: imageSnapshot({
getMatchOptions: (option) => {
const filename = option.context.kind.replace(' ', '');
return {
customSnapshotsDir: path.join(IMAGE_SNAPSHOT_DIR, filename),
};
},
}),
});
In my project I compile multiple bundles from source files in nested directories using rollup.
I had a gulpfile with the following code, which worked fine:
function build_app_js(file, name) {
return gulp.src(file)
.pipe(sourcemaps.init())
.pipe(rollup({format:'iife'}))
.pipe(terser())
.pipe(rename(name + '.js'))
.pipe(rename({suffix: '.min'}))
.pipe(sourcemaps.write())
.pipe(gulp.dest(js_apps_dir))
}
// call the above for multiple sets of file+app_name
But then I changed one of the dependencies in my ES6 code which I accessed by relative path into an npm package, so it is now in node_modules. Rollup needs a plugin to resolve this, so I changed the above to this:
.pipe(rollup({plugins: [resolveNodeModules()], format:'iife'}))
However this simply does not work.
I consulted rollup's docs on gulp, and adapted the example to my case, so it now looks like this:
function build_app_js(file, name) {
return rollup.rollup({
input: file,
plugins: [
resolveNodeModules()
]
}).then(bundle => {
return bundle.write({
file: js_apps_dir + '/' + name + '.js',
format: 'iife',
sourcemap: true
});
});
}
This works, but has no minification step, and I don't know how to add one.
More generally, this is a totally different paradigm from using pipe(), and I do not know how to make both work together.
Do I try to add minification in the Promise syntax, or do I wrap the Promise function in such a way that I can use it with pipe?
Answering own question after 8 days.
Minification can be achieved via rollup plugins, such as rollup-plugin-terser.
You just need to be careful with how you import them:
var rollup = require('rollup');
var resolveNodeModules = require('rollup-plugin-node-resolve');
//var terser = require('rollup-plugin-terser'); // WRONG
var {terser} = require('rollup-plugin-terser'); // CORRECT
function build_app_js(file, name) {
return rollup.rollup({
input: file,
plugins: [
resolveNodeModules(),
terser()
]
}).then(bundle => {
return bundle.write({
file: js_apps_dir + '/' + name + '.js',
format: 'iife',
sourcemap: true
});
});
}
If you import it the wrong way, you will get a terser() is not a function type error, which is because it will have imported terser as a module.
It's a bit annoying that different rollup-plugins can't be imported the same way, but hey.
TLDR: How to combine css-modules with normal sass, preferably in webpack.
The Setup:
I am working on the styling build process for an e-commerce website. The site's styles are currently done in sass along with the js through a gulp browserify build process.
I have recently added a single page app that is built using react with webpack and babel. Inside of that application I am taking advantage of css-modules provided by webpack to scope the class names to each react component.
The problem:
I would like to incorporate the styles from the webpack css-modules build in with the main styling bundle for the site. To do this, I was considering building a webpack configuration to build the styles for the whole site. The problem I have is how to get the styles which are currently built by the single page webpack configuration and inject just the style chunk into a global webpack configuration that handles styles for the whole site. I should mention that I would like to keep the two configurations as separate as possible
The Questions:
Is there a proper way of having decoupled webpack builds where one is still able to use chunks from the other?
If so, how do I do it so that the css-module setup stays in the single page configuration, and the extract-text-webpack part along with a boring sass build goes into a global configuarion?
If not, how should I go about having one section of sass go through the css-modules workflow, and still combine it with the bundle from the rest of the site.
Thanks in advance.
EDIT
based on #Alexandr Subbotin's answer, I have updated my webpack to look something like the code below. I did have to change names and paths because of the code belongs to my employer, so there may be slight errors.
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const JSDIR = './build/js/';
const STYLES = './build/css/bundle.css';
module.exports = {
entry : {
'styles' : './src/styles.scss',
'app' : './src/index.js',
// a javascript file that includes the root of the single page app.
'single-page' : './src/single-page/styles-entry.js',
},
output : {
path : JSDIR,
filename : '[name].js', // normally compiles my
publicPath: 'http://localhost:8080/',
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader : 'babel-loader',
query : {
presets: [
'react','es2015','stage-0',
]
},
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract('style?sourceMap', 'css?-url&sourceMap!sass?sourceMap'),
exclude : /\/single-page\//,
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract(
'style?sourceMap',
'css?-url&modules&importLoaders=1&localIdentName=SinglePage__[name]__[local]!sass?sourceMap'
),
include : /\/single-page\//,
}
]
},
plugins : [
new ExtractTextPlugin(STYLES, {
allChunks : true,
}),
],
resolve : {
alias: {
"eventEmitter/EventEmitter": "wolfy87-eventemitter",
},
extensions: ['', '.js','.jsx'],
},
}
If I understood your question you want to apply css-modules only to one part of your application and leave simple sass building process in other parts.
To do this you can use exclude and include options in loaders. I.e. if you have your single page application inside single-page directory your webpack config can be:
module: {
entry: {
// it is your global sass styles
application_css: './css/application.scss',
// it is main file of your SPA bundle. Somewhere inside you will use require('./styles.scss') that should be processed by css-modules
spa_index: './single-page/index.js'
},
loaders: [
...,
{
// This loader will build all your sass that are not in `single-page` directory
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css!sass'),
exclude: /\/single-page\//
},
{
// This loader will handle all your css module in `single-page` directory
test: /\.scss$/,
loader: 'style!css?modules!sass',
include: /\/single-page\//
},
],
...
}
So, in this case all css from single-page/ will use css modules, and the rest won't.
EDIT:
If you take a look in API section of ExtractTextPlugin documentation you find
The ExtractTextPlugin generates an output file per entry, so you must use [name], [id] or [contenthash] when using multiple entries.
In your example you have have two chunks with css (styles and single-page), but only one output ./build/css/bundle.css. If you change your output to ./build/css/[name].css your will have two css files: styles.css with your global css and single-page.css with SPA styles.
I want to combine all my scripts into one minified javascript file, but I'm having trouble combining them.
mix.browserify([
// ViewModels
'viewmodels.js'
], 'resources/assets/compiled/js/viewmodels.js')
mix.coffee([
// WebSocket Client
'client.coffee'
], 'resources/assets/compiled/js/').scripts([
// Vendor
'vendor/jquery.js',
'vendor/bootstrap.js',
'vendor/vue.js',
'vendor/sisyphus.js',
'vendor/leaflet.js',
'vendor/moment.min.js'
], 'resources/assets/compiled/js/vendor.js').scripts([
// Site & Helpers
'libs/laravel.js',
'libs/helpers.js'
], 'resources/assets/compiled/js/site.js').scripts([
// Combine Scripts
'resources/assets/compiled/js/vendor.js',
'resources/assets/compiled/js/client.js',
'resources/assets/compiled/js/site.js',
'resources/assets/compiled/js/viewmodels.js'
], 'public/js/all.js', './')
The files are created in resources/assets/compiled/js, so I've got:
client.js
site.js
vendor.js
viewmodels.js
The last task that's run is the scripts task combining the four files.
The elixir log states (I simplified the ouput):
Browserify (ViewModels)
CoffeeScript Compiled
Merging Vendor
Merging Site & Helpers
Merging Combine Scripts
... and these are the error messages I get:
File not found: ./resources/assets/compiled/js/vendor.js
File not found: ./resources/assets/compiled/js/site.js
I did the exact same thing with sass and styles and it worked perfectly.
mix.sass([
// Vendor
'resources/assets/sass/fontawesome/font-awesome.scss',
// Site
'resources/assets/sass/site/site.scss'
], 'resources/assets/compiled/css/').styles([
// Vendor
'resources/assets/css/bootstrap.min.css',
'resources/assets/css/hover-min.css',
'resources/assets/css/leaflet.css',
'resources/assets/compiled/css/font-awesome.css',
// Site
'resources/assets/compiled/css/site.css'
], 'public/css/all.css', './').version(
'public/css/all.css'
)
Why don't you merging the scripts all at once instead of doing it 3 times ?
Try like this
mix.coffee([
// WebSocket Client
'client.coffee'
], 'resources/assets/compiled/js/')
.scripts([
// Vendor
'resources/assets/js/vendor/jquery.js',
'resources/assets/js/vendor/bootstrap.js',
'resources/assets/js/vendor/vue.js',
'resources/assets/js/vendor/sisyphus.js',
'resources/assets/js/vendor/leaflet.js',
'resources/assets/js/vendor/moment.min.js',
// Site & Helpers
'resources/assets/js/libs/laravel.js',
'resources/assets/js/libs/helpers.js',
'resources/assets/compiled/js/client.js',
'resources/assets/compiled/js/viewmodels.js'
], 'public/js/all.js', './');