Webpack automatically require a file in all files...? - reactjs

Using Webpack and building an app in React.
In all my files, I have to include to type:
var React = require('React');
seems like a useless repetition.
Is there something I can add in the config file ofwebpack to import/require React in all my files?

You can use ProvidePlugin to automatically require React when needed.
Just add to your webpack config file:
var webpack = require('webpack');
module.exports = {
// Your configuration stuff.
plugins: [
new webpack.ProvidePlugin({
React: 'react'
})
]
};
Every time React is used in a file it will be auto-required/imported without having to do it explicitly.

You only need to require it once in the entry point. While I don't use react, I only include Angular, or any other library that I use, once. Here's an example of how it might look:
// app.ts (my entry point)
namespace app {
"use strict";
//////////// Conditional Requires for Development /////////////
/* istanbul ignore if: only necessary for development environment */
if (process.env.NODE_ENV === "development") {
require("../src/index.html");
}
//////////// Require CSS /////////////////////////////////////
require("../node_modules/codemirror/lib/codemirror.css");
require("./main.css");
//////////// Require Libraries ///////////////////////////////
var angular: IAngularStatic = require("angular");
require("../node_modules/angular-resource");
require("../node_modules/angular-ui-codemirror");
require("../node_modules/angular-sanitize");
//////////// Initialize Angular //////////////////////////////
angular.module("app", [
"ui.codemirror",
"ngResource",
"ngSanitize"
]);
//////////// Require Application Components //////////////////
require("./components/durian.js");
require("./components/testbox.js");
require("./moreapplicationfiles/");
}
This is one file, which I use as the jumping off point for all required libraries and application files.
Once Webpack has packed all of the files together it will do so in the order that I have listed here into one file, so just put React above all application files that use React and they will have access to all React methods and properties. The same advice goes for Flux, Redux, jQuery, or any other library. Of course, not all libraries play nice with Webpack, but it's rare that one doesn't.
As far as adding to the config file... You can also add in additional entry points which can include your JavaScript libraries, by listing all of the libraries in an array at the "entry." You just have to make sure that it will pack these libraries first, so test that they are in the correct order:
// In your webpack.config.js file
{
entry: [ "./node_modules/react", "./app.js"],
}

Related

Bundle CRA into single js file

I'm having a React App created with CRA, I need to deploy it as a widget.
People need to be able to include a js file and then just use the <App></App> Tag where ever they need it. Since CRA splits files I already tried ejecting the app, but failed miserably.
I already tried from similar questions the following:
combine-react-build-output-into-single-js-file
bundling without minification
the bundling without minification almost got my to the end. But now I would need to minify the resulting file.
This is my build.js file:
const rewire = require('rewire');
const defaults = rewire('react-scripts/scripts/build.js');
const config = defaults.__get__('config');
// Consolidate chunk files instead
config.optimization.splitChunks = {
cacheGroups: {
default: false
}
};
// Move runtime into bundle instead of separate file
config.optimization.runtimeChunk = false;
// JS
config.output.filename = '[name].js';
// CSS. "5" is MiniCssPlugin
config.plugins[5].options.filename = '[name].css';
config.plugins[5].options.publicPath = '../';
this file comes from the bundling without minification question. I'm now fairly clueless how to minify it and if it is really the right way to deploy.

How to extract multiple theme stylesheets with webpack?

I am trying to make a React app themeable. For now themes only consist of different sets of Sass variables which define different header colors, etc.
From my current understanding the ExtractTextPlugin seems to be my best bet as I don't want my styles to be inlined and rather have separate files per theme.
So I created two themes:
src/scss/themes/theme-a.scss
src/scss/themes/theme-b.scss
The themes import the basic layout and common styles and override the relevant variables.
But the only way I managed to make webpack create separate css files
for both themes was to create distinct entry points for each theme in
my webpack.prod.config:
entry: {
app: './src/js/init.js',
theme-a: './src/scss/themes/theme-a.scss',
theme-b: './src/scss/themes/theme-b.scss'
},
But adding a new entry point for every new theme that gets added feels wrong and I figure there must be a better way?
Here's your solution:
npm i --save-dev file-loader
In the loaders section, add this:
{
test: /themes\/.+\.scss$/,
loader: "file-loader?name=./compiled-themes/css/[name].css!css!sass"
},
There may be more scss files, if so there must be another section which bundles them as usual, but skips the themes:
{
test: /\.scss$/,
exclude: /themes\/.+\.scss$/,
loader: "css!sass"
},
The file loader writes files by filename, hash and extension so you are able to preserve the name.
Note the name=./compiled-themes/css/[name].css part, where [] vars are substituted.
https://github.com/webpack/file-loader
To avoid having to manually add the themes one possible solution is to create a function that reads contents of the themes folder and programatically add an entry for each *.scss file.
Something along the lines of this:
function getThemes(themePath) {
var themes = {};
fs.readdirSync(themePath).forEach(function(fileName) {
var fileNameWithPath = path.join(themePath, fileName);
var stat = fs.lstatSync(fileNameWithPath);
if (stat.isDirectory()) return;
if (!/\.scss$/.test(fileName)) return;
var nameWithoutExt = path.basename(fileName, '.scss');
themes[nameWithoutExt] = fileNameWithPath;
});
return themes;
}
var themes = getThemes('./src/scss/themes');
var config= {
entry: _.merge({ app: './src/js/init.js' }, themes),
// rest of options
};
This will require you to restart your dev-server or re-run you webpack build when adding new theme files though, but at least you won't have to touch your webpack config.

How to create a bundle using gulp without using "require" everywhere

Thanks for reading. I am new to gulp, so apologizing if its a dumb question. I have an AngularJS project with the following folder structure:
app/
app.js
modules/
mod1/
index.js
mod1.js
another.js
mod2/
... same structure as mod1
To create a bundle using browserify I am using this:
gulp.task('bundle', function() {
return browserify('app/app.js')
.bundle()
.pipe(vinylSource('bundle.js'))
.pipe(gulp.dest('public/js'));
});
To make this work, I have include require('mod1') ..require('another') and so on.
I always have to make sure that I am requiring the script that I need to use.
My goal is to create a bundle that includes all javascript file inside my app folder starting from app.js without getting into dependency conflicts and without me writing require('somefile').
You can get that by just using the gulp-concat plugin.
You just specify the paths to search. Because you're using angular and need the modules defined before everything else, I'd add the app first, then all the module definitions, then remaining directives and controllers etc after.
var gulp = require('gulp');
var concat = require('gulp-concat');
gulp.task('app-js', function() {
return gulp.src([
'./app/app.js',
'./app/**/mod*.js',
'./app/**/*.js',
])
.pipe(concat('bundle.js'))
.pipe(gulp.dest('public/js'))
});

Wanting To Optionally Add JavaScript code using Gulp

I've got a gulpfile.js that bundles using browserify and I want to be able to optionally add one line to one of my javascript files based on a variable like useMock. Below is my GulpFile.js build step
function bundle (bundler) {
return bundler
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('./dist'))
.pipe(browserSync.stream());
}
The last line of the file below is the one I want to optionally include.
module.exports = require('angular')
.module('AngularUApp', [
require('angular-ui-router'),
require('angular-sanitize'),
require('../../base'),
require('./home'),
require('./speaker'),
require('./author')
])
.config(enableHtml5Mode)
.name;
enableHtml5Mode.$inject = ['$locationProvider'];
function enableHtml5Mode($locationProvider) {
console.log('enableHtml5Mode');
$locationProvider.html5Mode(true);
}
// I want to optionally include this from my gulpfile.js
require('../mock');
I want to be able to have a production and dev build where the dev includes the extra line and production does not. If there is a better more recommended way to do this, please suggest.
I found the answer myself. Using the browserify api itself from this link:
https://github.com/substack/node-browserify#usage
var combinedArgs = merge(watchify.args, { debug: true });
var b = browserify(baseDir,combinedArgs);
b.add('angu/mock');
var watcher = watchify(b);
I had a problem earlier because I forgot the relative directory from gulp is different than from inside the JavaScript itself.

Load JavaScript and CSS files in folders in AngularJS

I have an AngularJS application and in the future, some developers in other teams will develop modules that will be installed as parts of it. So I defined the folder structure as below.
www/
index.html
app.js
modules/
modulesA/ -- will be copied when module A was installed
moduleA.js
moduleA.css
moduleA.partial.html
modulesB/ -- will be copied when module B was installed
moduleB.js
moduleB.css
moduleB.partial.html
Now I have a problem. When user installed module A, how to let AngularJS (and the application) load JS and CSS under its folder? Is there any library can load JS and CSS by folder so that I can put the code in index.html likes
<script src="/modules/**/*.js"></script>
<link src="/modules/**/*.css"/>
Otherwise, I have to add some placesholders in index.html and change the content when user installed a module, something like
<script src="/app.js"></script>
<!-- $$_JS_$$ -->
<link src="/app.css"/>
<!-- $$_CSS_$$ -->
AngularJS doesn't support what you want, but you could take a look at build tools such as Grunt or Gulp that let you "build" your application for you. In your case, these tools can look for CSS files and concatenate them into one single file. This way your index.html does not have to change if you ever add new modules.
GruntJS: http://gruntjs.com/
GulpJS: http://gulpjs.com/
Personally I use GulpJS, since it seems to be much faster & I found it easier to configure:
Included my configuration file below.
For example, the task "styles" will compile every css file it finds in the folders I specified, concatenate them, and drop them in the distribution folder.
Since there is an initial learning curve on how to use these tools, you can always integrate gulp or grunt at your own pace. For now you could let it build your css files & later expand it by concatenating JS as well and do various other tasks. In my opinion, its worth learning as it saves you so much time & effort.
var gulp = require("gulp");
var concat = require("gulp-concat");
var html2js = require("gulp-ng-html2js");
var sass = require("gulp-sass");
var clean = require("gulp-clean");
var streamqueue = require("streamqueue");
var ngDepOrder = require("gulp-ng-deporder");
var paths = {
"dist": "../server/staffing/static/",
"vendor": ['vendor/underscore/underscore.js',
'vendor/angular/angular.min.js',
'vendor/angular-route/angular-route.min.js',
'vendor/restangular/dist/restangular.min.js',
'vendor/angular-animate/angular-animate.min.js',
'vendor/angular-bootstrap/ui-bootstrap-0.7.0.min.js',
'vendor/angular-bootstrap/ui-bootstrap-tpls-0.7.0.min.js',
'vendor/angular-ui-router/release/angular-ui-router.min.js',
'vendor/angular-bootstrap-colorpicker/js/bootstrap-colorpicker-module.js',
'vendor/momentjs/min/moment.min.js'],
"scripts": ['app/**/*.js'],
"fonts": ['app-data/fonts/*.*'],
"templates": ['app/**/*.html'],
"styles": ['app/**/*.scss','vendor/angular-bootstrap-colorpicker/css/*.css']
}
gulp.task("watch", function () {
gulp.watch('app/**/*.js', ['scripts']);
gulp.watch('app/**/*.html', ['scripts'])
gulp.watch('app/**/*.scss', ['styles']);
})
gulp.task("default", ["clean"], function () {
gulp.start("scripts", "vendor", "styles", "fonts");
})
gulp.task("clean", function () {
return gulp.src(paths.dist, {read: false})
.pipe(clean({force: true}));
})
gulp.task("vendor", function () {
gulp.src(paths.vendor)
.pipe(concat("vendor.js"))
.pipe(gulp.dest(paths.dist + "js/"));
});
gulp.task("scripts", function () {
var stream = streamqueue({objectMode: true});
stream.queue(gulp.src(paths.scripts)
.pipe(ngDepOrder()));
stream.queue(gulp.src(paths.templates)
.pipe(html2js({moduleName: "templates"})));
return stream.done()
.pipe(concat("app.js"))
.pipe(gulp.dest(paths.dist + "js/"))
});
gulp.task("styles", function () {
gulp.src(paths.styles)
.pipe(sass())
.pipe(concat("staffing.css"))
.pipe(gulp.dest(paths.dist + "css/"))
})
gulp.task("fonts", function () {
gulp.src(paths.fonts).
pipe(gulp.dest(paths.dist + "fonts/"))
})
Check out the angular generator for Slush, it does what I think you want using gulp-bower-files and gulp-inject. You specify your app dependencies using bower, and these are collected and injected by gulp using gulp-inject, which then injects in your index.html the proper link/src/style tags that look very much like your own examples above. Modules' JS and CSS is also collected, minimized, concatenated and injected as well. It also compiles partials and injects those into $templateCache.
I have used it to automatically include dependencies from sub-folder modules/views using a project layout similar to yours.
Note that all your vendor dependencies will need to be bower packages that specify their dist files using the 'main' attribute in bower.json. Some packages do not do this properly, but it's easy to fork the package and add them yourself then point bower at your updated repo.

Resources