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.
Related
I have a react app (using create react app) and then a component library (using webpack directly). One component in the component library needs to load a png file in one of the components that it exports. In the webpack config for the component library I have a section such as:
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
This successfully results in a file like: 29b6b66cf1a691be2b3f.png in the component libraries output directory. The issue, is that when the application uses that component and the component attempts to load the image, the img element is <img ... src="29b6b66cf1a691be2b3f.png" /> and that fails to load, since that image actually lives in the component library folder (within the react application's node_modules/component-library/ at that point).
I have scoured the internet to the best of my ability, and can not seem to figure out what the best solution would be here. Any help is appreciated. I will quickly offer clarification if needed.
UPDATE: I have discovered CopyWebpackPlugin but it is quite unfortunate that this would require me to eject the "parent" application from create react app. Something I would very much prefer to avoid.
UPDATE2: Current plan is to try following something like what is explained here. The jist of it is to utilize something like rewire to avoid needing to eject and still be able to edit the webpack config via something like:
// in ./build.js
const rewire = require('rewire');
const defaults = rewire('react-scripts/scripts/build.js');
const config = defaults.__get__('config');
// edit webpack config values here
... I will answer my own question here if I find that this approach works.
Alright, well this felt like it was much messier than it needed to be, but I was able to figure out a way to accomplish this. The pieces were as follows.
First, needed to install copy-webpack-plugin. This was not as simple as it might sound, because I needed to find one that would not conflict with the version of webpack required by my react-scripts (create react app). I determined that copy-webpack-plugin#6.4.1 was the last version to support webpack v4, so I installed that and then added the following to my package.json:
"overrides": {
"copy-webpack-plugin": {
"webpack": "4.44.2"
}
},
this ensured that it would use the version of webpack that my react-scripts installation was expecting.
Then, I also needed to install rewire, and add the following to a file called build.js:
const rewire = require('rewire');
const defaults = rewire('react-scripts/scripts/build.js');
const config = defaults.__get__('config');
const CopyPlugin = require("copy-webpack-plugin");
const patterns = [
{
context: "node_modules/component-library/path/",
from: "*.png",
to: "."
},
]
if(config.plugins === undefined){
config.plugins = [new CopyPlugin({patterns})]
}else{
config.plugins.push(new CopyPlugin({patterns}))
}
// below lets it work in dev mode too
if(config.devServer === undefined){
config.devServer = {
writeToDisk: true
}
}else{
config.devServer.writeToDisk = true;
}
Finally, had to update my build script to be:
"scripts": {
...
"build": "node ./build.js",
...
},
Does anyone know how to change the names of the build's generated JS files, without using webpack? ex: every time you have a build change the filenames: 'bundle_v1.js', 'chunk_v2.js' (It doesn't necessarily need to be standardized).
Context: every time we publish our project through Azure, whether in development or production environment, we need to ctrl+f5 to clear the cache and show the changes.
I've already tried to add some configs in the config-overrides.js file but I wasn't successful.
Myconfig-overrides.js:
const {
addBabelPlugin,
override,
} = require('customize-cra');
const path = require('path');
module.exports = override(
addBabelPlugin([
'babel-plugin-root-import',
{
rootPathPrefix: '#/',
rootPathSuffix: 'src',
},
]),
);
I'm trying to import multiple files with a certain extension in a folder:
const allEntries = require.context('../static/blog', true, '/\.md/')
but I'm getting:
Unhandled Rejection (TypeError): __webpack_require__(...).context is not a function
I'm using Nextjs and require the files in one of the pages. Something seems off here?
Edit: I don't necessarily need to do it via require I just want to be able to import/require multiple files at once without knowing the filename or how many of the files are in a folder.
You can give the following a try in webpack:
const glob = require('glob');
const allEntries = glob.sync("../static/blog/*.md");
The glob will return an array of files. The array will contain all files with .md extension in the ../static/blog/ folder. Eventough there is a package it shouldn't be required to install the package.
Try using require context npm library.
$ npm i --save require-context
In your file:
// Load globally into all modules.
require('require-context/register')
// Load locally as a function.
var requireContext = require('require-context');
function requireAll(r) { r.keys().forEach(r); }
requireAll(requireContext('../static/blog', true, /\.md$/));
From what I understand you are very close, from the error you are using webpack's require.context
const allEntries = require.context('../static/blog', true, '/\.md/')
console.log(allEntries.keys()) // all the files found in the context
allEntries.keys().forEach(allEntries) // require them all
const imageDirectory = path.join(process.cwd(), '/public/dirname');
const imageFilenames = await fs.readdir(imageDirectory)
// Store the file names in an array and use it.
webpack.require is basically using webpack, make sure what you're using is webpack in fact
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"],
}
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.