My task is to introduce library to existing create react app based application.
This library need to be build to separate chunk and should not contain any contenthash in name. Ideally should be build to buildDir/js/widget.js and that is.
Currently all my ts are compiled to js during build and are served with contenthash in name.
I don't know how to build widget.js from src/widget/index.ts because entry point is src/index.ts and it never catch src/widget/index.ts because it is not imported anywhere in main entry point.
This widget.js later will be imported in thirdparty web apps via <script> tag and it will be used to initialize some library like MyLibrary.init(...) so I think webpack should also have some info so this one widget.js should export its methods in special way to the browser during importing external script.
What is best way to get this build proces to work. Also it could be really nice to have it also during development with hot updates.
I don't want contenthash in resulting buildDir/js/widget.js because I don't want to ask my customers every time I have new version to update their <script src="..."> for new file name.
Should I eject this CRA? I'm not sure even if I add another entry point that I will be able to control output file name for one entry point as it is and for another without contenthash.
Or maybe it will be better to create separate webpack config (next to unejected CRA) for this widget but then how to run everything in development mode with hot updates?
I'm using webpack 4.42.0 here in this project.
for your case maybe you need this:
https://dev.to/zhiyueyi/include-your-react-widgets-in-any-web-page-emj
https://github.com/ZhiyueYi/demo-react-web-widget
Related
I am building a SPA with Vue (Quasar actually) in which I need to be able to:
Load the contents of a CSS file into a JS variable (or Vue data
property) at runtime
This CSS file should be produced at build time
from a SCSS file
I don’t want to load a pre-made CSS file, I want to be able to author the CSS code via SASS.
I also don’t want to compile the CSS from SCSS at runtime, e.g. on every app load.
In other words I have the following workflow in mind:
Author the CSS in a pre-defined SCSS file that is part of my project structure
At build time (or at run-dev time) I want that this SCSS is compiled into a CSS file
Then at runtime, in one of my Vue components, I want to load the previously produced CSS code as string into a variable
The reasoning for that is that this CSS code will then be fed into and iframe (via postMessage-ing) and the iframe will use CSSStyleSheet’s insertRule() to apply the styles to the page.
How should I configure my project and packages so that this can happen? One thing that I found already is that I might need to use the raw-loader but how do I prepare the CSS file when building the project so that the raw-loader can get it at runtime?
From an initial look you have two problems here both of which are relatively simple.
The first one is you need to include a scss compiler plugin during your projects build step. Which one you use will depend on any existing tooling you may be using. Otherwise, you can just drop in https://www.npmjs.com/package/node-sass
The second issue is how to acquire the css at runtime. You have a couple options here. You can compile the file into your bundle or you could retrieve it at runtime.
Runtime would keep your bundle small and allow you to serve the css normally but this requires a server to serve it. Compile time would be faster to load initially but increase your bundle size.
If you are using webpack you could use the raw loader you linked but if you are not currently using webpack that is probably out of scope.
You could do this by adding a new step to your build that converts the css into a String literal which would alleviate the need to load it at runtime but increase your bundle side.
For loading at runtime, you could easily retrieve the file via ajax from an http server.
I have found the following solution:
Install the "raw-loader" loader
Import the SCSS using the following statement:
import style from '!raw-loader!sass-loader!./my-styles.scss'
Note: the "!" at the beginning is to override the default loaders configuration. In my case Quasar chains the "style-loader" for SCSS files by default (to output a tag in the head) so I have to disable it in this case.
And now I have the compiled CSS code in the style variable.
First, run the following.
npm install path sass
Aftre that...
const path = require("path");
const sass = require("sass");
const css = sass.compile(path.join(__dirname, "style.scss")).css;
console.log(css);
I have been pulling my hair out for 3 weeks trying to get this to work, and I can't figure out where the gap in my understanding is.
I am building a library of components for an authorable CMS. My vision is to have a set of n thin entrypoints, all of which will have statically imported dependencies that are requested when the entrypoint is run via script tag.
Per my understanding, webpack can chunk shared dependencies together via splitChunks plugin, and those dependencies can be automatically loaded via the bundle-loader plugin.
However, when I call an entrypoint bundle via script tag, the automatic dependency import does not occur - only when I use dynamic import() syntax within my source files does dynamic import occur - but that's because import() itself is dynamic.
How can I configure webpack to pull in statically dependent chunks?
Check out Paragons (see section: Code Splitting). Then take a look at CodeSplitPage which is wrapped in a Loadable using a dynamic import.
The HtmlWebpackPlugin is what you're looking for. You can configure it to generate entry.html output files in your dist folder, which you can then use in an Express application, or import into your non-Node server rendering to get the full list of <script> tag.
I have a two-year-old AngularJs 1.x project, which is built with Gulp for development and Grunt for production (don't ask me why; I don't know either).
The build process is basically:
Compile all scss files into one css file
Merge all JS files into one JS file. We are not using any import mechanism. Each file is basically one of AngularJs' controller, component, service or filter. Something like this:
angular.module("myApp").controller("myCtrl", function() {//...});
Merge all html templates into one JS file. Each template is hardcoded with $templateCache.
Moving assets like images and fonts into the build folder.
Moving third-party libraries into the build folder.
Now I want to switch to webpack for this project. I want to incrementally modernize this project, but the first step would be just building it with webpack with a similar process like the above. I would like to keep the code base as much the same as possible. I don't want to add import for all the JS files yet. There are too many. I would also like to add a babel-loader.
I have some basic concepts about webpack, but never really customized the configuration myself.
Would anyone please give me some pointers? Like which loaders/plugins would I need, etc.? Thanks!
My process to do such a transition was gradual, I had a similar Grunt configuration.
These are my notes & steps in-order to transition to Webpack stack.
The longest step was to refactor the code so it will use ES6 imports/exports (yeah, I know you have said that it is not a phase that you wanna make, but it is important to avoid hacks).
At the end each file looks like that:
//my-component.js
class MyComponentController { ... }
export const MyComponent = {
bindings: {...},
controller: MyComponentController,
template: `...`
}
//main.js
import {MyComponent} from 'my-component'
angular.module('my-module').component('myComponent', MyComponent);
In order not going over all the files and change them, we renamed all js files and added a suffix of .not_module.js.
Those files were the old untouched files.
We added grunt-webpack as a step to the old build system (based on Grunt).
It processed via Webpack all the new files (those that are without .not_module.js suffix).
That step produced only one bundle that contains all the files there were converted already, that file we have added to concat step.
One by one, each converted file gradually moved from being processed by Grunt tasks to be processed by Webpack.
You can take as a reference that webpack.config.
Good luck.
I am finally trying to bring a modern build system to my app, and I'm hoping someone can help. I think I need a few paradigm shifts.
So this is how my app is structured:
/src
/components
/Base
/App.jsx
/Pages.jsx
/...
/Page1
/Page1Component1.jsx
/Page1Component2.jsx
/...
/Page2
/Page2Component1.jsx
/Page2Component2.jsx
/...
/...
/libs
/bootstrap.js
/jquery.js
/react.js
/...
/scripts
/index.js
/utils.js
/styles
/main.css
/html
/index.html
Right now I have gulp set up to do this:
Make a new folder /dest to put everything
Combine everything in /scripts, name it main.js, put it in dest
Combine everything in /libs, name it libs.js, put it in dest
Combine everything in /components, run it through babel, name it comps.js, put it in dest
Copy the one /html file and one /styles file into dest
Then here is how the app runs:
Open index.html
That page requests main.js
main.js requests libs.js and comps.js
Everything works
But here is the issue I'm running into: A lot of stuff here relies on other stuff being global. index.js waits for comps.js and libs.js to load, then calls ReactDOM.render(<App />...), which means both ReactDOM and App need to be global.
Now I'm trying to add something that needs require(), and I try to use Browserify for it. But Browserify takes the code that needs the require and wraps it up in a way that, I believe, makes nothing global.
I realize that I need to turn my app into actual modules, instead of just a bunch of files that concatenate and call each other. And I know that avoiding global variables will be a good thing in the long run. But I'm having a really hard time figuring out how.
For example, I have >50 React modules. It seems wrong to add module.exports to every single one of those, and then import them all to the main file. Further, some of the things in /lib are libraries that don't export as modules, they're made to be run in the <head> tag, like Google Charts.
So I guess my questions are:
Where should my module exports be, and how do they fit into my gulp tasks? Do I concatenate then export?
How do I deal with libraries that aren't modules?
Is my app really poorly laid out, and I just need to restructure from scratch?
Thanks, and sorry about the rambley question.
First, there's nothing wrong with your file structure.
Second, the best thing you can do is follow the "one module, one file" rule. That does mean adding module.exports or export default to every single file. That's just good JavaScript. But it doesn't mean importing them all into your main file, which brings us to:
Third, think in modularity. Files should require or import precisely what they need and nothing they don't. For example, if your App uses Page1 and Page1 uses Page1Component1, then that's how your imports should work:
App -> Page1 -> Page1Component1
-> Page1Component2
-> Page2 -> Page2Component1
-> ...
This ensure separation of concerns and protects your code from easy-to-trigger errors later on (like those from nested dependency changes). And your build system should generate one file (but you can tackle performance later if needed with chunking and so forth).
And you're correct that in this kind of structure, using Browserify or Webpack will ensure that nothing is global - and that's a good thing (though I will note that you can tell them explicitly to expose components, which is sometimes necessary for libraries).
And that leaves libraries that you don't control that you can't import. This does not apply to Bootstrap, jQuery, or React, which all have require-able modules from NPM. But assuming that you have a library you didn't mention that is not available through NPM, you can still include it globally in your HTML with a script tag and tell Browserify or Webpack to expose it for requiring.
I have a single page app which comprises of a JS bundle based on Browserify and Coffeescript.
In a certain usecase, I need to create an adhoc page (Detached from the SPA) which needs to access a library (Kendo to be specific), which is part of the browserified bundle and the adhoc page would have some simple JS based on kendo.
The question is how do I load/access the library outside the Single Page Application (If I try loading it, the browser says that the library is not found)?
Using RequireJS could be an option as specified here. But, I dont want to use another library just for this purpose. I think there must be a way to "require" the library without requireJS because it is already working in the Single Page Application.
Please help.. Thanks!
Browserify rewrites your module paths like ../moduleA/file.js into an internal module id like 23 when packing.
Every require statement will also be rewritten, a statement like this:
var moduleA = require('../moduleA/file.js');
Becomes this:
var moduleA = require(23);
To get access to a particular library, you can do to things:
1) find the internal id via debugger and then require the module via it (this is quite fragile, because the internal id could change with every build)
2) package another file into your bundle with the following contents:
var kendo = require('kendo');
window.kendo = kendo;
Afterwards, you can simply access kendo as a page global.