Simple NPM package bundling/vendoring? - javascript

Disclaimer: I am primarely a backend developer with no extensive FE knowledge.
I am writing a non-SPA Golang web application that generates HTML, which is then sent to the user.
Because I'd like to update and monitor my Javascript/CSS dependencies better, I want to switch to using NPM with a package.json file instead of manually downloading and appending CSS and Javascript libraries. These are the typical jquery, bootstrap and fontawesome.
In addition to this, I have a single Javascript file per page for interactive content.
e.g.
+ js
lib.js -> jquery, bootstrap, fontawesome
- home -> specific JS
- account -> specific JS
...
+ css
theme.css
custom.css
However, I see no simple solution to just npm install and export the installed packages to a vendor.js file, minified.
Iv'e looked at webpack (go-webpack), but this horribly complex with the whole tree shaking, bundling and shimming. In addition, webpack expects you to run a development server when serving assets locally, do some chunk magic and still refer to global libraries in every JS file. (to prevent from being tree-shaken away)
Is there an easier way to go from a package.json file to a minified, bundled set of assets?

TLDR: ‘You can’t see the forest for the trees’ - Just get a minimal configuration of webpack.config.js working before diving into more advanced details, such as tree shaking, chunking, etc...
You need to use a bundler, such as Webpack or Parcel, to bundle all your JavaScript assets into a single JavaScript file. I think you're trying to do too much to start with:
webpack-dev-server
Tree Shaking
Chunking
As these are more advanced concepts... Perhaps you could start by initially creating a single JavaScript bundle (or a bundle on a per page basis) to be used by your application. This wouldn't be as complex and would require entry points into the following files within your application:
Application's JavaScript index (This should load the JavaScript used by your application)
CSS index. (Ideally, you have a root styling file which loads other application styling files)
Now set-up the appropriate loaders and plugins for your application's assets, such as the MiniCssExtractPlugin, file-loader, etc..., to load and handle your applications' assets. Once everything is working, simply attach this generated bundle in a <script> tag within your root html index page, rather than initially configuring a webpack-dev-server. This will allow your application to use your bundled JavaScript file without the need to configure a webpack-dev-server. To create new bundles create custom commands within the scripts section of your package.json file, something along the lines of:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack -p --progress --config webpack.config.js",
"dev-build": "webpack --progress -d --config webpack.config.js",
"watch": "webpack --progress -d --config webpack.config.js --watch"
},
Only after everything is working should you worry about more advanced performance gains, such as: chunking/treeshaking/etc... Take a look at the following tutorials as they may help: Intro to Webpack and Full Stack Web application. Note the second tutorial is a little dated as the defacto now would be to use create-react-app cli instead of setting up the build configurations yourself for a react project, BUT the principles are sound and show you how to go about setting up your own build configuration.
Hopefully that helps!

Related

How to run an Electron application from source (not bundle)

I'm new to Electron, and trying to help maintain an application whose developer has left. The resources/app folder consists of (at least) three things:
The app/lib/bundle.js, which contains the entire application, bundled and minified. This is what the app seems to actually run.
Node modules for all the code written by the developer. These are in TypeScript, and are in the structure node_modules/#mainmodule/submodule/src/.../something.ts. Each of these also has a node_modules/#mainmodule/submodule/package.json and node_modules/#mainmodule/submodule/tsconfig.json
Finally, for each of these, a corresponding lib folder: node_modules/#mainmodule/submodule/src/.../something.js. The lib folder has Javascript corresponding to each of the TypeScript, as well as map files showing how they correspond. It is these Javascript files that are minified and included in the bundle, which is actually run.
The source TypeScript is relatively clear and I can follow most of it. But to really understand it I need to set breakpoints on it and run it in a debugger (e.g. VS Code). However, when running the app, Electron doesn't run it from the TypeScript (in src), or even the individual Javascript (in lib), but rather from bundle.js. Bundle.js is a giant file that, besides being minified, is too big to even load properly in my editor.
My question
How can I tell Electron to run the app not from the bundle.js, but from the individual src/...ts TypeScript, or, failing that, from the individual src/...js JavaScript?
If that's not possible, what is the proper way to use a debugger, given the source, when the Electron application is bundled? I have full source but, when I invoke Electron, it runs out of the bundle: how I can change this?
I'm new to Electron and Node, so if I'm making an elementary mistake, please clarify.
Update with progress so far
I've made a lot of progress in getting down to source, but not all the way there.
The Electron app starts with electron-main.js, which loads things like server.js and other files. These all run from source.
Eventually, it creates a minimal window with the following code:
<head>
...
<script type="text/javascript" src="./bundle.js" charset="utf-8"></script>
</head>
bundle.js is then loaded in the window. The files is far too big and unscrutable (minified) to be of much use. But, as I said, the source is all available too.
However, bundle.map.js contains is complete: it contains sources, names, mappings, sourcesContent, which is enough, in principle, to reconstruct everything. Moreover, for almost all of the sources, the corresponding source file is available and obvious.
I believe I need to replace the <script type="text/javascript" src="./bundle.js" charset="utf-8"></script> with a includer.js which:
Includes all files for which I can figure out their matching source file
Uses the sourcesContent for anything else
/Progress to date...
Since the project is set up to run things from a bundle at the moment, it's likely that the project can only run things from the bundle, unless you change the config (which can only be done if you have some idea of what the overall structure is in the first place, which you're trying to get a grasp on to begin with). In other words, the most likely approach to look at how things are interlocking and to analyze and change the logic in the application will be to generate a new bundle.
Very often, the process of generating a new bundle will be contained in the project's root folder's package.json. If you have:
the-big-app/node_modules
then you can probably look at
the-big-app/package.json
and look at the scripts contained within it. There will probably be something along the (very general) lines of:
{
"name": "the-big-app",
"scripts": {
"lint": "eslint .",
"build": "webpack && tsc --build tsconfig.node.json",
"watch": "nodemon --exec npm run start -e ts,tsx,scss,html",
"run": "npx electron build/node/main.js",
"start": "npm run build && npm run run"
},
Each of these properties refers to a runnable NPM script. You're likely to have a build script - if you have such a script and type npm run build, it should then generate a new bundle, which can then be executed. If there is no build script, look around to see which other scripts look like they might do something useful, and execute them. (Back up the existing bundle and other files in the directory first, just in case.)
Look at the values for each NPM script property so you can do further research into what they do and how they might relate to turning the source code into something that runs. Just for example, above, doing
"build": "webpack && tsc --build tsconfig.node.json",
in my app, will
(1) Run Webpack to construct a bundle for the renderer process
(2) Run tsc to compile the TypeScript code inside the-big-app/src/main-process/ into JavaScript that can then be executed by Electron
Look for something similar in your package.json to see what's happening, which will inform you on how it can be tweaked and debugged.
As Electron's docs say, the browser code can be debugged via the devtools. Debugging the main process is harder - you may need to call Electron with the inspect flag, among others.
As for the question of if/how things can be run directly from source TypeScript and not from a bundle - it's possible to do this for the main process with ts-node (2). I don't think it's possible for a renderer process, because the "page" needs to see a plain .js file, like any webpage - and, similarly, can't run TypeScript directly, also like normal browsers and webpages can't run TypeScript directly.
To add to the above answer, I have a Typescript React app that uses Webpack, which you can compare against. You can step through its code for both the main and renderer processes:
VSCode Config
Webpack Code
You also need to build with sourcemaps enabled. Once done you can step through Typescript code line by line.

Making vue.js component library. Avoid rebuilding it after each edit

Intro: I've generated two projects with vue-cli ~4.2.0:
parent-app - main project
dummylib - library which is imported by parent-app. Has a bunch of .vue components inside.
Currently, parent-app works fine in dev mode with dummylib being imported into it. All dummylib's vue-components are rendering ok.
Problem: I want to edit dummylib and see changes on the fly, as it takes place with parent-app: without having to rebuild it after each code modification.
My current library development process:
(dummylib): yalc publish - assuming it has been built already
(parent-app): yalc link dummylib
(parent-app): npm serve - start local development
Editing dummylib...
(dummylib): npm build - !!! Want to avoid this step !!!
(dummylib): yalc publish --push - After this, I see my edits from (4) being applied...
So are there any options to avoid (5)? I've also thought about monorepo, but decided not to have it currently.
Finally, got it working by adding:
"start": "vue-cli-service build --target lib --name dummylib src/main.js --watch --mode development"
to scripts section in package.json

Create react app different public/index.html for production/dev

I am working on a react app and a js project. So basically two things which are on the same website. Now I want to minify the plain js code in production. My first approach was to concatenate all js files, run them through a compressor lib and include the compressed js lib to index.html. However, I want this only in production so my question is, is it possible to have 2 public/index.html with different includes depending on dev or production? or is there another way to solve this?
Well, if I were you I would create several tasks on the package.json file, something like "prod" and "dev", I do not know if you are using plain Webpack or create-react-app cli, in my case with Webpack I serve the plain files when I am developing and I generate a dist folder with all the minimized files for production.
Something like this:
"scripts": {
"prod": "./node_modules/.bin/webpack -p --mode production",
"dev": "./node_modules/.bin/webpack-dev-server --config ./webpack.config.js --mode development",
},
So the main thing to learn here is that you do not need to mantain two index.html files, but create tasks that handle the dev and prod mode for you.

How to set up Parcel bundling in a Chrome extension for the whole source directory?

I'm trying to create a Chrome extension.
However, once I've tried integrating Parcel I am in a bit of a pickle. I'd like to use Parcel for compatibility with old Chrome versions + for splitting my code into multiple files.
My folder structure:
When I try to make this command work:
//package.json
"scripts": {
"build": "parcel build src/js/script.js", }
I end up only with the 'script.js' inside the '/dist' folder, but I want to create a dist folder that I can package and publish. I basically want to get all my html, css, js (etc.) inside a dist folder. Can this be done?
How would you go about adding a whole framework, like Vue or React e.g. to make the popup or options page?
Parcel 2 has a first-party WebExtensions transformer. It will pick up every files mentioned in manifest.json plus some other files like what's under _locales and it works fairly well!
.parcelrc file:
{
"extends": "#parcel/config-webextension"
}
Install command:
npm install parcel #parcel/config-webextension
Build command:
parcel build manifest.json
✨ Built in 1.18s

How to make Cordova App Live Reload ,especially built by webpack and run in device or emulator

I'm new to use cordova.One way to live reload cordova app I know is to use plugin 'cordova-plugin-browsersync'.But My App was built by webpack,now I want to live reload in Browser,I must run 'webpack-dev-server' first and run 'cordova run browser -- --live-reload'.Can I achive the function to Live Reload more easy and debug live reload in emulator?
I used npm package live-server to handle the reloading for the browser platform. Have it watch the platforms/browser/www directory. Your build system likely has a watch mode, in which it can detect changes and output the compiled result as well. You also need to call cordova prepare after your build finishes, which can be achieved with nodemon.
To put it all together in a full example:
Have your source code in /src.
Run your build tool in watch mode (ex, webpack --watch, or parcel --watch) and output to /www
Run nodemon watching /www and have it run cordova prepare. The prepare command will copy your files from www to your platform directories. (ex: nodemon --watch www --exec \"cordova prepare\")
Run live-server watching the /platforms/browser/www folder
Viola!
This results in a semi-fast live-reload environment with cordova in the browser platform. As this is a lot of things to run at once, you can run all of your scripts in parallel using npm-run-all.
A final script in package.json might look like this:
"scripts": {
"live-build": "webpack --watch --output-path=www ....",
"live-watch": "nodemon --watch www --exec \"cordova prepare\" --ext html,css,js",
"live-serve": "live-server --watch=\"platforms/browser/www\"",
"start": "npm-run-all -c -n -l -p live-build live-watch live-serve"
}
And then you'd just call npm start to run your entire live-reload environment. This will need to be tweaked for your specific project but should give you a general idea of how it could be accomplished.
I just ran into the same problem and yet haven't found a ready solution, so below is what I did and further steps of my plan to solve it.
I've downloaded cordova-plugin-browsersync
cordova plugin add cordova-plugin-browsersync didn't work, so I manually copied it to plugins folder, updated cordova's package.json and installed the plugin's node modules from cordova-plugin-browsersync folder.
After that the app seems to update pretty fast if anything is modified in the www folder.
Now have to solve how to output intermediate bundle files from webpack-dev-server, which it doesn't do by default. I've found write-file-webpack-plugin, but it's not outputting all the files to the build folder, so might not work very well for this purpose.
So my plan is to
create a webpack.config.cordova.js file where code compression is off
setup any app that watches the src folder and calls a node.js script
which script programmatically compiles with that webpack config, outputting to cordova's www/

Categories