upgrade rails 6 to 7, "No loader is configured for '.scss' - ruby

I'm trying to upgrade rails 6, but when I launch server via "bin/dev" command, I get this error: "
10:58:29 web.1 | started with pid 11431
10:58:29 css.1 | started with pid 11432
10:58:29 js.1 | started with pid 11433
10:58:29 worker.1 | started with pid 11436
10:58:29 css.1 | yarn run v1.22.5
10:58:29 js.1 | yarn run v1.22.5
10:58:29 css.1 | warning ../../package.json: No license field
10:58:29 js.1 | warning ../../package.json: No license field
10:58:29 css.1 | $ sass ./app/assets/stylesheets/application.sass.scss ./app/assets/builds/application.css --no-source-map --load-path=node_modules --watch
10:58:29 js.1 | $ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --watch
10:58:29 js.1 | ✘ [ERROR] No loader is configured for ".scss" files: app/javascript/stylesheets/application.scss
10:58:29 js.1 |
10:58:29 js.1 | app/javascript/application.js:6:7:
10:58:29 js.1 | 6 │ import './stylesheets/application.scss';
10:58:29 js.1 | ╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10:58:29 js.1 |
10:58:29 js.1 | 1 error
10:58:29 js.1 | [watch] build finished, watching for changes...
0:58:32 web.1 | => Booting Puma
10:58:32 web.1 | => Rails 7.0.2.3 application starting in development
10:58:32 web.1 | => Run `bin/rails server --help` for more startup options
10:58:32 css.1 | Sass is watching for changes. Press Ctrl-C to stop.
10:58:32 css.1 |
10:58:32 web.1 | Puma starting in single mode...
10:58:32 web.1 | * Puma version: 5.6.4 (ruby 3.1.2-p20) ("Birdie's Version")
10:58:32 web.1 | * Min threads: 5
10:58:32 web.1 | * Max threads: 5
10:58:32 web.1 | * Environment: development
10:58:32 web.1 | * PID: 11431
10:58:32 web.1 | * Listening on http://127.0.0.1:3000
10:58:32 web.1 | * Listening on http://[::1]:3000
10:58:33 web.1 | Use Ctrl-C to stop
10:58:33 worker.1 | 2022-04-25T08:58:33.680Z pid=11436 tid=aqg INFO: Booted Rails 7.0.2.3 application in development environment
10:58:33 worker.1 | 2022-04-25T08:58:33.681Z pid=11436 tid=aqg INFO: Running in ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
10:58:33 worker.1 | 2022-04-25T08:58:33.681Z pid=11436 tid=aqg INFO: See LICENSE and the LGPL-3.0 for licensing details.
10:58:33 worker.1 | 2022-04-25T08:58:33.681Z pid=11436 tid=aqg INFO: Upgrade to Sidekiq Pro for more features and support: https://sidekiq.org
10:58:33 worker.1 | 2022-04-25T08:58:33.681Z pid=11436 tid=aqg INFO: Booting Sidekiq 6.4.2 with redis options {}
Server starts, but no stylesheets are apllied. I tried to search for something on this topic, but all the results were about webpacker.
package.json
{
"name": "testing",
"private": true,
"dependencies": {
"#hotwired/stimulus": "^3.0.1",
"#hotwired/turbo-rails": "7.1.1",
"#rails/actiontext": "^6.1.5",
"#rails/ujs": "^6.1.5",
"#zxing/browser": "^0.1.1",
"#zxing/library": "^0.19.1",
"animate.css": "^4.1.1",
"aos": "^2.3.4",
"autoprefixer": "^10.4.5",
"chart.js": "^3.6.1",
"chartkick": "^4.1.1",
"esbuild": "^0.14.38",
"esbuild-sass-plugin": "^2.2.6",
"flatpickr": "^4.6.9",
"postcss": "^8.4.12",
"sass": "^1.50.1",
"stimulus_reflex": "3.4.1",
"swiper": "^6.8.0",
"tailwindcss": "^3.0.24",
"tailwindcss-stimulus-components": "^3.0.1",
"toastr": "^2.1.4",
"trix": "^1.2.0"
},
"engines": {
"node": "16.x"
},
"version": "0.1.0",
"scripts": {
"build:css": "sass ./app/assets/stylesheets/application.sass.scss ./app/assets/builds/application.css --no-source-map --load-path=node_modules",
"build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds"
}
}
tailwind.config.js
module.exports = {
content: [
'./app/views/**/*.html.haml',
'./app/helpers/**/*.rb',
'./app/assets/stylesheets/**/*.css',
'./app/javascript/**/*.js'
]
}
Procfile.dev
web: bin/rails server -p 3000
css: yarn build:css --watch
js: yarn build --watch
worker: bundle exec sidekiq -C config/sidekiq.yml
application.html.haml
!!!
%html.text-gray-900.leading-tight.max-w-screen{:translate => "no", :lang => t('language_code')}
%head
= display_meta_tags
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
%title= content_for?(:title) ? yield(:title) : "testin"
%link{:href => "https://unpkg.com/swiper/swiper-bundle.css", :rel => "stylesheet"}/
%link{:href => "https://unpkg.com/swiper/swiper-bundle.min.css", :rel => "stylesheet"}/
%meta{:content => content_for?(:description) ? yield(:description) : "testin", :name => "description"}/
%meta{:content => "width=device-width,initial-scale=1", :name => "viewport"}/
= csrf_meta_tags
= csp_meta_tag
= action_cable_meta_tag
= stylesheet_link_tag "application", "data-turbo-track": "reload"
%body.bg-white.w-full.overflow-x-hidden.static.min-h-screen{"data-controller" => "modal", "data-modal-allow-background-close" => "false"}
.w-full.mx-auto.flex.flex-col.h-screen
= render 'layouts/navigation'
.w-full.h-full.flex-grow.z-0.md.overflow-y-auto{:role => "main"}
= yield
= toastr_flash
= render 'layouts/footer'
:javascript
window.locale = "#{escape_javascript I18n.locale}"
app/javascript/application.js
// Entry point for the build script in your package.json
import Rails from '#rails/ujs';
import * as ActiveStorage from '#rails/activestorage';
import './channels';
import './stylesheets/application.scss';
import flatpickr from "flatpickr";
import "flatpickr/dist/flatpickr.min.css";
import "chartkick/chart.js"
import "./controllers"
// import Swiper JS
import Swiper from 'swiper';
import SwiperCore, { Navigation, Pagination } from 'swiper/core';
SwiperCore.use([Navigation, Pagination]);
var mySwiper = new Swiper('.swiper-container', {
// Optional parameters
autoHeight: true,
calculateHeight: true,
direction: 'horizontal',
loop: true,
// If we need pagination
pagination: {
el: '.swiper-pagination',
type: 'bullets',
},
// Navigation arrows
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
// And if we need scrollbar
scrollbar: {
el: '.swiper-scrollbar',
},
});
// Animation on scroll
import AOS from 'aos';
import 'aos/dist/aos.css';
Rails.start();
ActiveStorage.start();
global.toastr = require('toastr');
require('trix');
require('#rails/actiontext');
// Google Maps callback
window.initMap = function (...args) {
const event = document.createEvent('Events');
event.initEvent('google-maps-callback', true, true);
event.args = args;
window.dispatchEvent(event);
};
document.addEventListener('turbo:load', () => {
flatpickr(".datepicker", {
enableTime: true,
minDate: "today"
})
AOS.init({ duration: 1200, offset: 300 });
var mySwiper = new Swiper('.swiper-container', {
// Optional parameters
direction: 'horizontal',
loop: true,
// If we need pagination
pagination: {
el: '.swiper-pagination',
},
// Navigation arrows
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
// And if we need scrollbar
scrollbar: {
el: '.swiper-scrollbar',
},
});
});
Any ideas what goes wrong? I updated the app based on this video: https://www.youtube.com/watch?v=SjdV_1k1QWY&t

Uncomment your gem and bundle install. Looks like your including sass, but rails doesn't know to include sass/scss.
Use Sass to process CSS
gem "sassc-rails"
I had this same issue running a Rails project when starting with this command and I was really confused why Rails didn't know what to do upon initialization
rails new clickit -d=postgresql -j=esbuild -c=sass

Related

Including socket.io when compiling assets using Laravel Mix results in error on Windows 10

Trying to work with Broadcasting using Laravel Echo/Redis/Socket.io, with the following versions:
node v6.11.3
npm v5.4.2
Laravel 5.4
npm run dev (or production) results in a dependency error where module 'fs' is required, although it was considered optional when installing socket.io.
I've uninstalled npm and started from scratch, sifted through tons of google results referencing a possible solution, can anyone assist?
Below is a copy of my webpack config:
let path = require('path');
let glob = require('glob');
let webpack = require('webpack');
let Mix = require('laravel-mix').config;
let webpackPlugins = require('laravel-mix').plugins;
let dotenv = require('dotenv')
/*
|--------------------------------------------------------------------------
| Load Environment Variables
|--------------------------------------------------------------------------
|
| Load environment variables from .env file. dotenv will never modify
| any environment variables that have already been set.
|
*/
dotenv.config({
path: Mix.Paths.root('.env')
});
/*
|--------------------------------------------------------------------------
| Mix Initialization
|--------------------------------------------------------------------------
|
| As our first step, we'll require the project's Laravel Mix file
| and record the user's requested compilation and build steps.
| Once those steps have been recorded, we may get to work.
|
*/
Mix.initialize();
/*
|--------------------------------------------------------------------------
| Webpack Context
|--------------------------------------------------------------------------
|
| This prop will determine the appropriate context, when running Webpack.
| Since you have the option of publishing this webpack.config.js file
| to your project root, we will dynamically set the path for you.
|
*/
module.exports.context = Mix.Paths.root();
/*
|--------------------------------------------------------------------------
| Webpack Entry
|--------------------------------------------------------------------------
|
| We'll first specify the entry point for Webpack. By default, we'll
| assume a single bundled file, but you may call Mix.extract()
| to make a separate bundle specifically for vendor libraries.
|
*/
module.exports.entry = Mix.entry().get();
/*
|--------------------------------------------------------------------------
| Webpack Output
|--------------------------------------------------------------------------
|
| Webpack naturally requires us to specify our desired output path and
| file name. We'll simply echo what you passed to with Mix.js().
| Note that, for Mix.version(), we'll properly hash the file.
|
*/
module.exports.output = Mix.output();
/*
|--------------------------------------------------------------------------
| Rules
|--------------------------------------------------------------------------
|
| Webpack rules allow us to register any number of loaders and options.
| Out of the box, we'll provide a handful to get you up and running
| as quickly as possible, though feel free to add to this list.
|
*/
let plugins = [];
if (Mix.options.extractVueStyles) {
var vueExtractTextPlugin = Mix.vueExtractTextPlugin();
plugins.push(vueExtractTextPlugin);
}
let rules = [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: Mix.options.extractVueStyles ? {
js: 'babel-loader' + Mix.babelConfig(),
scss: vueExtractTextPlugin.extract({
use: 'css-loader!sass-loader',
fallback: 'vue-style-loader'
}),
sass: vueExtractTextPlugin.extract({
use: 'css-loader!sass-loader?indentedSyntax',
fallback: 'vue-style-loader'
}),
less: vueExtractTextPlugin.extract({
use: 'css-loader!less-loader',
fallback: 'vue-style-loader'
}),
stylus: vueExtractTextPlugin.extract({
use: 'css-loader!stylus-loader?paths[]=node_modules',
fallback: 'vue-style-loader'
}),
css: vueExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader'
})
}: {
js: 'babel-loader' + Mix.babelConfig(),
scss: 'vue-style-loader!css-loader!sass-loader',
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
less: 'vue-style-loader!css-loader!less-loader',
stylus: 'vue-style-loader!css-loader!stylus-loader?paths[]=node_modules'
},
postcss: Mix.options.postCss,
preLoaders: Mix.options.vue.preLoaders,
postLoaders: Mix.options.vue.postLoaders
}
},
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader' + Mix.babelConfig()
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader']
},
{
test: /\.html$/,
loaders: ['html-loader']
},
{
test: /\.(png|jpe?g|gif)$/,
loaders: [
{
loader: 'file-loader',
options: {
name: path => {
if (! /node_modules|bower_components/.test(path)) {
return 'images/[name].[ext]?[hash]';
}
return 'images/vendor/' + path
.replace(/\\/g, '/')
.replace(
/((.*(node_modules|bower_components))|images|image|img|assets)\//g, ''
) + '?[hash]';
},
publicPath: Mix.options.resourceRoot
}
},
{
loader: 'img-loader',
options: Mix.options.imgLoaderOptions
}
]
},
{
test: /\.(woff2?|ttf|eot|svg|otf)$/,
loader: 'file-loader',
options: {
name: path => {
if (! /node_modules|bower_components/.test(path)) {
return 'fonts/[name].[ext]?[hash]';
}
return 'fonts/vendor/' + path
.replace(/\\/g, '/')
.replace(
/((.*(node_modules|bower_components))|fonts|font|assets)\//g, ''
) + '?[hash]';
},
publicPath: Mix.options.resourceRoot
}
},
{
test: /\.(cur|ani)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]',
publicPath: Mix.options.resourceRoot
}
}
];
let extensions = ['*', '.js', '.jsx', '.vue'];
if (Mix.ts) {
rules.push({
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
});
extensions.push('.ts', '.tsx');
}
let sassRule = {
test: /\.s[ac]ss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
};
if (Mix.preprocessors) {
sassRule.exclude = Mix.preprocessors.map(preprocessor => preprocessor.test());
}
rules.push(sassRule);
if (Mix.preprocessors) {
Mix.preprocessors.forEach(preprocessor => {
rules.push(preprocessor.rules());
plugins.push(preprocessor.extractPlugin);
});
}
module.exports.module = { rules };
/*
|--------------------------------------------------------------------------
| Resolve
|--------------------------------------------------------------------------
|
| Here, we may set any options/aliases that affect Webpack's resolving
| of modules. To begin, we will provide the necessary Vue alias to
| load the Vue common library. You may delete this, if needed.
|
*/
module.exports.resolve = {
extensions,
alias: {
'vue$': 'vue/dist/vue.common.js'
}
};
/*
|--------------------------------------------------------------------------
| Stats
|--------------------------------------------------------------------------
|
| By default, Webpack spits a lot of information out to the terminal,
| each you time you compile. Let's keep things a bit more minimal
| and hide a few of those bits and pieces. Adjust as you wish.
|
*/
module.exports.stats = {
hash: false,
version: false,
timings: false,
children: false,
errors: false
};
process.noDeprecation = true;
module.exports.performance = { hints: false };
/*
|--------------------------------------------------------------------------
| Devtool
|--------------------------------------------------------------------------
|
| Sourcemaps allow us to access our original source code within the
| browser, even if we're serving a bundled script or stylesheet.
| You may activate sourcemaps, by adding Mix.sourceMaps().
|
*/
module.exports.devtool = Mix.options.sourcemaps;
/*
|--------------------------------------------------------------------------
| Webpack Dev Server Configuration
|--------------------------------------------------------------------------
|
| If you want to use that flashy hot module replacement feature, then
| we've got you covered. Here, we'll set some basic initial config
| for the Node server. You very likely won't want to edit this.
|
*/
module.exports.devServer = {
headers: {
"Access-Control-Allow-Origin": "*"
},
historyApiFallback: true,
noInfo: true,
compress: true,
quiet: true
};
/*
|--------------------------------------------------------------------------
| Plugins
|--------------------------------------------------------------------------
|
| Lastly, we'll register a number of plugins to extend and configure
| Webpack. To get you started, we've included a handful of useful
| extensions, for versioning, OS notifications, and much more.
|
*/
plugins.push(
new webpack.ProvidePlugin(Mix.autoload || {}),
new webpackPlugins.FriendlyErrorsWebpackPlugin({ clearConsole: Mix.options.clearConsole }),
new webpackPlugins.StatsWriterPlugin({
filename: 'mix-manifest.json',
transform: Mix.manifest.transform.bind(Mix.manifest),
}),
new webpack.LoaderOptionsPlugin({
minimize: Mix.inProduction,
options: {
postcss: Mix.options.postCss,
context: __dirname,
output: { path: './' }
}
})
);
if (Mix.browserSync) {
plugins.push(
new webpackPlugins.BrowserSyncPlugin(
Object.assign({
host: 'localhost',
port: 3000,
proxy: 'app.dev',
files: [
'app/**/*.php',
'resources/views/**/*.php',
'public/js/**/*.js',
'public/css/**/*.css'
]
}, Mix.browserSync),
{
reload: false
}
)
);
}
if (Mix.options.notifications) {
plugins.push(
new webpackPlugins.WebpackNotifierPlugin({
title: 'Laravel Mix',
alwaysNotify: true,
contentImage: Mix.Paths.root('node_modules/laravel-mix/icons/laravel.png')
})
);
}
if (Mix.copy.length) {
new webpackPlugins.CopyWebpackPlugin(Mix.copy);
}
if (Mix.entry().hasExtractions()) {
plugins.push(
new webpack.optimize.CommonsChunkPlugin({
names: Mix.entry().getExtractions(),
minChunks: Infinity
})
);
}
if (Mix.options.versioning) {
plugins.push(
new webpack[Mix.inProduction ? 'HashedModuleIdsPlugin': 'NamedModulesPlugin'](),
new webpackPlugins.WebpackChunkHashPlugin()
);
} else if (Mix.options.hmr) {
plugins.push(
new webpack.NamedModulesPlugin()
);
}
if (Mix.options.purifyCss) {
let PurifyCSSPlugin = require('purifycss-webpack');
// By default, we'll scan all Blade and Vue files in our project.
let paths = glob.sync(Mix.Paths.root('resources/views/**/*.blade.php')).concat(
Mix.entry().scripts.reduce((carry, js) => {
return carry.concat(glob.sync(js.base + '/**/*.vue'));
}, [])
);
plugins.push(new PurifyCSSPlugin(
Object.assign({ paths }, Mix.options.purifyCss, { minimize: Mix.inProduction })
));
}
if (Mix.inProduction && Mix.options.uglify) {
plugins.push(
new webpack.optimize.UglifyJsPlugin(Mix.options.uglify)
);
}
plugins.push(
new webpack.DefinePlugin(
Mix.definitions({
NODE_ENV: Mix.inProduction
? 'production'
: ( process.env.NODE_ENV || 'development' )
})
),
new webpackPlugins.WebpackOnBuildPlugin(
stats => global.events.fire('build', stats)
)
);
if (! Mix.entry().hasScripts()) {
plugins.push(new webpackPlugins.MockEntryPlugin(Mix.output().path));
}
module.exports.plugins = plugins;
/*
|--------------------------------------------------------------------------
| Mix Finalizing
|--------------------------------------------------------------------------
|
| Now that we've declared the entirety of our Webpack configuration, the
| final step is to scan for any custom configuration in the Mix file.
| If mix.webpackConfig() is called, we'll merge it in, and build!
|
*/
if (Mix.webpackConfig) {
module.exports = require('webpack-merge').smart(
module.exports, Mix.webpackConfig
);
}
Add the following to your Webpack config:
node: {
fs: "empty"
}
source here
EDIT
in your gulpfile.js add :
Elixir.webpack.mergeConfig({
node: {
fs: 'empty',
}
});
exemple :
var elixir = require('laravel-elixir');
require('laravel-elixir-vue');
Elixir.webpack.mergeConfig({
node: {
fs: 'empty',
}
});
...
OR IN YOUR webpack.config.js
edit like this :
mix.webpackConfig({
node: {
fs: "empty"
},
resolve: {
alias: {
"handlebars" : "handlebars/dist/handlebars.js"
}
},
});
After this error was resolved through the answer below, I received the error:
"the request of a dependency is an expression".
The following article helped clear up this additional error: source
This was the additional code that was added to my webpack.config.js:
let fs = require('fs');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
module.exports = {
target: 'node',
externals: nodeModules
}
Hopefully this helps someone else.

Webpack with React: is there something I am missing?

This question will be a bit long, but I need to explain the context, so be patient, please.
I am working on an Reacj/Ruby application structured in the following way:
<my_app>
|
|_____be/
|
|_____fe/
| |
| |_____node_module/
| |_____public/
| | |_____index.html
| | |_____index.jsx
| | |_____index.test.js
| | |_____bundle.js
| |_____src/
| |_____app/
| | |_____app.jsx
| | |_____app.test.js
| | |_____app.css
| |_____contents/
| | |_____contents.jsx
| | |_____contents.test.js
| | |_____contents.css
| |_____footer/
| | |_____footer.jsx
| | |_____footer.test.js
| | |_____footer.css
| |_____header/
| | |_____header.jsx
| | |_____header.teste.js
| | |_____header.css
| |_____package.json
| |_____index.jsx
| |_____index.test.js
| |_____index.css
|_____config.ru
|_____Gemfile
|_____Gemfile.lock
|_____integrations.json
|_____package.json
|_____webpack.config.js
It is a mix of pure Ruby (no Rails, no Sinatra) and ReactJS, where app, contents, footer and reader are ReactJS components. The idea is separating completely the backend be from the frontend fe, orchestrated by webpack and Rack, where I am going to use fetch to grab dynamical data from tye backend.
The application, after bundled with Webpack, will be run by Rack. The Rack::Static middleware will deal with serving the static assets built by npm run build and a Ruby gem I created will redirect the calls made by de frontend to a set of POROs (Plain Old Ruby Objects) which will provide de dynamic data. It is a small framework, as you may see. A concept I am trying to prove.
When it comes to fe, inside it everything is fine. When I enter its directoty and do npm test all tests run fine, and when I run npm start it runs fine too.
To make things simple in this test, all the ReactJS components do is write a single word. Like this:
app.jsx
import React from 'react';
import './app.css';
import Header from '../header/header.jsx';
import Contents from '../contents/contents.jsx';
import Footer from '../footer/footer.jsx';
export default class App extends React.Component {
render() {
return (
<div className="app">
<Header />
<Contents />
<Footer />
</div>
);
}
}
And this:
header.jsx
import React from 'react';
import './header.css';
export default class Header extends React.Component {
render() {
return (
<p>Header</p>
);
}
}
This way, when I run npm start inside fe, all I see in my browser (at http://localhost:3000) is
Header
Contents
Footer
Well, everything fine until this point. But I need to bundle the frontend app with Webpack. This is my configuration:
webpack.config.js
var path = require('path');
module.exports = {
entry: path.resolve(__dirname, 'fe/src/') + '/index.js',
output: {
path: path.resolve(__dirname,'fe/public/'),
filename: 'bundle.js'
},
devServer: {
inline: true,
contentBase: './public',
port: 3333
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}]
}
}
As you may see, I am creating bundle.js at fe/public. And my Rack::Static is configured to serve the index.html inside fe/public to all static requests, while my gem deals with the dynamical ones.
It happens that, although all modules are correctly installed and everything is bundled correctly, I see nothing when I run my app with rackup. No error, no problem... and no words! Just a blank browser screen.
What exactly am I missing?
EDIT:
package.json
{
"name": "emerald_application",
"title": "Emerald Framework Application",
"version": "0.1.0",
"private": true,
"dependencies": {
"bootstrap": "^3.3.7",
"fb": "^1.1.1",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-router": "^4.0.0"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-core": "^6.24.1",
"babel-loader": "^7.0.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"react-scripts": "0.9.5",
"webpack": "^2.5.1",
"webpack-dev-server": "^2.4.5"
},
"scripts": {
"start": "npm run serve | npm run dev",
"dev": "webpack-dev-server --progress --colors --port 8090"
}
}
No, I haven't used create-react-app. But this is not a problem, because the fe part is running fine, i.e., the ReactJS part runs fine by itself and I know enough about ReactJS apps to create them even without create-react-app, specially one so small.
I solved the issue by manking some changes to the code.
First of all, I edited the webpack.config.js.
webpack.config.js
var path = require('path');
module.exports = {
entry: path.resolve(__dirname, 'fe/src/') + '/index.jsx',
output: {
path: path.resolve(__dirname, 'public'), // <<== THIS
filename: 'bundle.js'
},
devServer: {
inline: true,
contentBase: './app',
port: 3333
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: [ "node_modules" ],
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}]
}
}
As you may see, this is going to make Webpack put the bundle.js file in a public directory at the root of my app. After that I created an index.html file inside the same public directory. Pointing to an index.html inside fe/src would create a lot of trouble with the paths to images and other resources, which now will be put at public/resources where it will be easier to refer to them at the pages created. My index.html file now reads:
index.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
After doing this, the app wasn't still running. Webpack couldn't find the node modules installed. They were inside the fe dir, then I just created a symlink with
$ ln -sf fe/node_modules
and then webpack run perfectly well and created the bundle.
This was my main goal, isolate the frontend completely inside the fe directory and be able at the same time to run this application from outside this dir, where I may run the complete application (backend and frontend) with a single command and under a single process. This will make the deploy easier at Heroku and other similar services.
I thank all those who took time to help me with this. This was the last step to have my web development framework running. Now it is just a matter of improving it even more.

Browsersync reloading the page instead of injecting css

So after my previous problem got solved, I'm now facing a different one. I'm using Browsersync to watch for file changes, and it works perfectly, but instead of injecting css changes, it realods the whole page whenever my css file is changed.
Here is my gulpfile:
var elixir = require('laravel-elixir');
var gulp = require('gulp');
/*
|--------------------------------------------------------------------------
| Elixir Asset Management
|--------------------------------------------------------------------------
|
| Elixir provides a clean, fluent API for defining some basic Gulp tasks
| for your Laravel application. By default, we are compiling the Sass
| file for our application, as well as publishing vendor resources.
|
*/
elixir(function(mix) {
mix.sass('comingsoon/soon.scss', 'public/assets/comingsoon/css/soon.css')
.scripts('comingsoon/soon.js', 'public/assets/comingsoon/js/soon.js')
.browserSync({
files: [
'app/*.*',
'app/**/*.*',
'public/assets/**/*.*'
],
open: 'external',
proxy: 'gate7.dev:81',
host: 'gate7.dev',
port: 80,
notify: false
});
});
Figured it out. I had to be specific about the files' extensions.
var elixir = require('laravel-elixir');
var gulp = require('gulp');
/*
|--------------------------------------------------------------------------
| Elixir Asset Management
|--------------------------------------------------------------------------
|
| Elixir provides a clean, fluent API for defining some basic Gulp tasks
| for your Laravel application. By default, we are compiling the Sass
| file for our application, as well as publishing vendor resources.
|
*/
elixir(function(mix) {
mix.sass('comingsoon/soon.scss', 'public/assets/comingsoon/css/soon.css')
.scripts('comingsoon/soon.js', 'public/assets/comingsoon/js/soon.js')
.browserSync({
files: [
'app/*.*',
'app/**/*.*',
'public/assets/**/*.css',
'public/assets/**/*.js'
],
open: 'external',
proxy: 'gate7.dev:81',
host: 'gate7.dev',
port: 80,
notify: false
});
});

Deploy Foundation for Apps on Heroku

I am trying to deploy an app created with "Foundation for Apps" on Heroku with no success.
Package.json:
{
"name": "foundation-apps-template",
"version": "1.0.3",
"scripts": {
"start": "gulp",
"postinstall": "bower install"
},
"dependencies": {
"bower": "^1.3.12",
"connect-modrewrite": "^0.7.9",
"front-matter": "^0.2.0",
"gulp": "^3.8.10",
"gulp-autoprefixer": "^1.0.1",
"gulp-concat": "^2.4.2",
"gulp-connect": "^2.2.0",
"gulp-load-plugins": "^0.8.0",
"gulp-ruby-sass": "^0.7.1",
"gulp-uglify": "^1.0.2",
"gulp-util": "^3.0.1",
"rimraf": "^2.2.8",
"run-sequence": "^1.0.2",
"through2": "^0.6.3"
},
"devDependencies": {
"connect-modrewrite": "^0.7.9",
"front-matter": "^0.2.0",
"gulp": "^3.8.10",
"gulp-autoprefixer": "^1.0.1",
"gulp-concat": "^2.4.2",
"gulp-connect": "^2.2.0",
"gulp-load-plugins": "^0.8.0",
"gulp-ruby-sass": "^0.7.1",
"gulp-uglify": "^1.0.2",
"gulp-util": "^3.0.1",
"rimraf": "^2.2.8",
"run-sequence": "^1.0.2",
"through2": "^0.6.3"
},
"private": true
}
gulpfile.js
// FOUNDATION FOR APPS TEMPLATE GULPFILE
// -------------------------------------
// This file processes all of the assets in the "client" folder, combines them with the Foundation
// for Apps assets, and outputs the finished files in the "build" folder as a finished app.
// 1. LIBRARIES
// - - - - - - - - - - - - - - -
var gulp = require('gulp'),
$ = require('gulp-load-plugins')(),
rimraf = require('rimraf'),
sequence = require('run-sequence'),
path = require('path'),
modRewrite = require('connect-modrewrite'),
router = require('./bower_components/foundation-apps/bin/gulp-dynamic-routing');
// 2. SETTINGS VARIABLES
// - - - - - - - - - - - - - - -
// Sass will check these folders for files when you use #import.
var sassPaths = [
'client/assets/scss',
'bower_components/foundation-apps/scss'
];
// These files include Foundation for Apps and its dependencies
var foundationJS = [
'bower_components/fastclick/lib/fastclick.js',
'bower_components/viewport-units-buggyfill/viewport-units-buggyfill.js',
'bower_components/tether/tether.js',
'bower_components/angular/angular.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-ui-router/release/angular-ui-router.js',
'bower_components/foundation-apps/js/vendor/**/*.js',
'bower_components/foundation-apps/js/angular/**/*.js',
'!bower_components/foundation-apps/js/angular/app.js'
];
// These files are for your app's JavaScript
var appJS = [
'client/assets/js/app.js'
];
// 3. TASKS
// - - - - - - - - - - - - - - -
// Cleans the build directory
gulp.task('clean', function(cb) {
rimraf('./build', cb);
});
// Copies user-created files and Foundation assets
gulp.task('copy', function() {
var dirs = [
'./client/**/*.*',
'!./client/templates/**/*.*',
'!./client/assets/{scss,js}/**/*.*'
];
// Everything in the client folder except templates, Sass, and JS
gulp.src(dirs, {
base: './client/'
})
.pipe(gulp.dest('./build'));
// Iconic SVG icons
gulp.src('./bower_components/foundation-apps/iconic/**/*')
.pipe(gulp.dest('./build/assets/img/iconic/'));
// Foundation's Angular partials
return gulp.src(['./bower_components/foundation-apps/js/angular/components/**/*.html'])
.pipe(gulp.dest('./build/components/'));
});
// Compiles Sass
gulp.task('sass', function() {
return gulp.src('client/assets/scss/app.scss')
.pipe($.rubySass({
loadPath: sassPaths,
style: 'nested',
bundleExec: true
})).on('error', function(e) {
console.log(e);
})
.pipe($.autoprefixer({
browsers: ['last 2 versions', 'ie 10']
}))
.pipe(gulp.dest('./build/assets/css/'));
});
// Compiles and copies the Foundation for Apps JavaScript, as well as your app's custom JS
gulp.task('uglify', function() {
// Foundation JavaScript
gulp.src(foundationJS)
.pipe($.uglify({
beautify: true,
mangle: false
}).on('error', function(e) {
console.log(e);
}))
.pipe($.concat('foundation.js'))
.pipe(gulp.dest('./build/assets/js/'))
;
// App JavaScript
return gulp.src(appJS)
.pipe($.uglify({
beautify: true,
mangle: false
}).on('error', function(e) {
console.log(e);
}))
.pipe($.concat('app.js'))
.pipe(gulp.dest('./build/assets/js/'))
;
});
// Copies your app's page templates and generates URLs for them
gulp.task('copy-templates', ['copy'], function() {
return gulp.src('./client/templates/**/*.html')
.pipe(router({
path: 'build/assets/js/routes.js',
root: 'client'
}))
.pipe(gulp.dest('./build/templates'))
;
});
// Starts a test server, which you can view at http://localhost:8080
gulp.task('server:start', function() {
$.connect.server({
root: './build',
port: process.env.PORT || 5000,
livereload: false
});
});
// Builds your entire app once, without starting a server
gulp.task('build', function() {
sequence('clean', ['copy', 'sass', 'uglify'], 'copy-templates', function() {
console.log("Successfully built.");
})
});
// Default task: builds your app, starts a server, and recompiles assets when they change
gulp.task('default', ['build', 'server:start'], function() {
// Watch Sass
gulp.watch(['./client/assets/scss/**/*', './scss/**/*'], ['sass']);
// Watch JavaScript
gulp.watch(['./client/assets/js/**/*', './js/**/*'], ['uglify']);
// Watch static files
gulp.watch(['./client/**/*.*', '!./client/templates/**/*.*', '!./client/assets/{scss,js}/**/*.*'], ['copy']);
// Watch app templates
gulp.watch(['./client/templates/**/*.html'], ['copy-templates']);
});
When I deploy, the app successfully build with one exception:
> gulp
> foundation-apps-template#1.0.3 start /app
[22:41:04] Using gulpfile ~/gulpfile.js
[22:41:04] Starting 'clean'...
[22:41:04] Starting 'build'...
[22:41:04] Starting 'server:start'...
[22:41:04] Starting 'default'...
[22:41:04] Finished 'server:start' after 323 ms
[22:41:04] Server started http://localhost:23921
[22:41:04] Finished 'build' after 343 ms
[22:41:04] Finished 'default' after 40 ms
[22:41:04] Starting 'sass'...
[22:41:04] Finished 'clean' after 386 ms
[22:41:04] Starting 'copy'...
State changed from starting to up
[22:41:05] Starting 'uglify'...
{ [Error: spawn bundle ENOENT]
showProperties: true,
errno: 'ENOENT',
message: 'spawn bundle ENOENT',
code: 'ENOENT',
syscall: 'spawn bundle',
path: 'bundle',
plugin: 'gulp-ruby-sass' }
name: 'Error',
stack: 'Error: spawn bundle ENOENT\n at exports._errnoException (util.js:746:11)\n at Process.ChildProcess._handle.onexit (child_process.js:1046:32)\n at child_process.js:1137:20\n at process._tickCallback (node.js:355:11)',
showStack: false,
[22:41:08] Finished 'sass' after 3.64 s
[22:41:08] Finished 'uglify' after 3.28 s
Successfully built.
After that, when I open the browser, I see the website, without CSS styles.
https://fierce-escarpment-9048.herokuapp.com/assets/css/app.css
404 Not Found
I suspect that - because of that exception with sass - the CSS file was not generated and - therefore - is not reachable to the server.
Any suggestion how I can fix it?
The specific errors you have posted actually relate to JavaScript, and most likely server-side JavaScript in the form of Node.js. The "ENOENT" is specific to errors reported from Node.js' libuv component ( https://github.com/joyent/node/blob/master/deps/uv/include/uv.h ), and as you can see from the provided link relates to "no such file or directory".
So, your problem from the error logs/gulpfile.js is that the 'default' action initiates the task comprising of concurrent actions 'build' and 'server-start' (gulpfile.js, line 144). The 'build' task itself is a function (line 137) that initiates a sequence starting with 'clean' (line 138) to which we should return. But first, 'server-start'... your server does start: "Starting 'server:start'... Finished 'server:start' after 323 ms... Server started http://localhost:23921...State changed from starting to up." So, you can see the matching output of "Starting [x]... Finished [x]" pairs captured in the logs. This is significant.
Returning to the 'build' task. That causes 'clean', followed by the concurrent actions of 'copy', 'sass' and 'uglify'; it is within this latter group that your problem occurred. Firstly, note we have "Starting 'clean'... Finished 'clean' after 386 ms" - again, we have the matched pair - and clean must occur before copy/sass/uglify. These are concurrent actions, and your problem is that the logged output is written apparently haphazardly as these tasks occur (thats true of the original overlapping build and start-server tasks too). So, we can see all of 'copy', 'sass' and 'uglify' start... but only 'sass' and 'uglify' finish! And, we have 'copy' start, and an otherwise unmatched/disassociated error message. Your error has arisen from the failure to 'copy', not from 'sass'! You failed to copy, and the (Node.js-based) server was raising "no such file or directory".
Sorry, I couldn't interpret what its failed to copy (perhaps content from the 'client' directory), but its concerning absent content - perhaps even a simple misspelt filename, or something very similar. You should probably examine closely the file content in your directory.
Found this guide where explains how to deploy a Foundation for apps to heroku, I already tried it and works like a charm. Hope it helps.

Grunt fails trying to load an empty module

I'm a bit stuck with my Jenkins setup on OSX Lion 10.7.3.
I'm using Grunt in my webapp to run Jasmine tests, build less, create cache manifest etc. Everything works on my laptop Lion 10.7.5, but on the server box grunt fails from time to time with the following error:
$ grunt less
module.js:340
throw err;
^
Error: Cannot find module ''
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:362:17)
at require (module.js:378:17)
at ChildProcess.<anonymous> (/usr/local/lib/node_modules/grunt-cli/bin/grunt:44:3)
at ChildProcess.EventEmitter.emit (events.js:99:17)
at Process._handle.onexit (child_process.js:678:10)
This is intermittent, it fails approximately once out of five runs and is not task specific. It fails with the same rate when running grunt manifest or grunt test.
Once thing I noticed is that when it works it takes a second or two until the task starts executing, but when it fails it fails immediately.
I tried to remove node_modules, npm cache clear, reinstalling grunt-cli. Nothing works.
Here's my package.json:
{
"name": "webapp",
"version": "0.0.0",
"dependencies": {},
"devDependencies": {
"grunt": "0.4.0rc7",
"grunt-contrib-copy": "0.4.0rc7",
"grunt-contrib-concat": "0.1.2rc6",
"grunt-contrib-coffee": "0.4.0rc7",
"grunt-contrib-uglify": "0.1.1rc6",
"grunt-contrib-compass": "0.1.1rc8",
"grunt-contrib-jshint": "0.1.1rc6",
"grunt-contrib-mincss": "0.4.0rc7",
"grunt-contrib-connect": "0.1.1rc6",
"grunt-contrib-clean": "0.4.0rc6",
"grunt-contrib-htmlmin": "0.1.1rc7",
"grunt-contrib-imagemin": "0.1.1rc8",
"grunt-contrib-livereload": "0.1.0rc8",
"grunt-contrib-jasmine": "~0.3.2",
"grunt-contrib-less": "0.5.0",
"grunt-manifest": "0.4.0",
"grunt-jslint": "0.2.5",
"grunt-bower-hooks": "~0.2.0",
"grunt-usemin": "~0.1.7",
"grunt-regarde": "~0.1.1",
"grunt-requirejs": "~0.3.1",
"grunt-mocha": "~0.2.2",
"grunt-open": "~0.1.0",
"matchdep": "~0.1.1"
},
"engines": {
"node": ">=0.8.0"
}
}
npm and node versions:
$ npm -version
1.2.11
$ node --version
v0.8.20
I have now stripped down both packages.json and Gruntile.js:
$ cat package.json
{
"name": "webapp",
"version": "0.0.0",
"dependencies": {},
"devDependencies": {
"grunt": "0.4.0rc7",
"grunt-manifest": "0.4.0",
"matchdep": "~0.1.1"
},
"engines": {
"node": ">=0.8.0"
}
}
$ cat Gruntfile.js
'use strict';
module.exports = function (grunt) {
// load all grunt tasks
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
grunt.initConfig({
manifest: {
generate: {
options: {
basePath: 'app/',
exclude: ['js/lib/amp/com.vaultus.api.WebApiAggregated.cache.js', 'js/lib/amp/com.vaultus.api.DebugWebApiAggregated.cache.js'],
timestamp: true
},
src: [
'index-hybrid.html',
'*.xml',
'js/**/*.js',
'css/**/*.css',
'css/images/**/*',
'i18n/**/*.js',
'template/**/*.html'
],
dest: 'app/cache-manifest.mf'
}
}
});
grunt.registerTask('build', [
'manifest'
]);
grunt.registerTask('default', ['build']);
};
No luck :(
We were hitting this issue on our CI builds.
After a bit of digging it looks like this was a bug in grunt-cli 0.1.6 and has been fixed in 0.1.7 of grunt-cli.

Resources