diff --git a/v3-docs/docs/about/build-tool.md b/v3-docs/docs/about/build-tool.md new file mode 100644 index 0000000000..e2849bcf04 --- /dev/null +++ b/v3-docs/docs/about/build-tool.md @@ -0,0 +1,380 @@ +# Build System + +This guide covers how Meteor's build system compiles your app. + +After reading this guide, you'll know: + +1. What the Meteor build tool does +2. How to choose between Meteor Bundler and Rspack integration +3. How JavaScript transpilation works +4. How to configure CSS processing +5. How to use Hot Module Replacement +6. How to write custom build plugins + +## What does it do? + +The Meteor build system is the actual command line tool that you get when you install Meteor. You run it by typing the `meteor` command in your terminal, possibly followed by a set of arguments. Read the [CLI documentation](/cli/) or type `meteor help` in your terminal to learn about all of the commands. + +The Meteor build tool is what compiles, runs, deploys, and publishes all of your Meteor apps and packages. It's Meteor's built-in solution to the problems also solved by tools like Grunt, Gulp, Webpack, Browserify, Nodemon, and many others. + +Starting with Meteor 3.3, you can use the **Modern Build Stack** which includes optimizations with SWC transpilation. With Meteor 3.4, you can integrate **Rspack** as your application bundler for even faster builds, smaller bundle sizes, and modern bundling features. See the [Modern Build Stack overview](/about/modern-build-stack) for details. + +### Reloads app on file change + +After executing the `meteor` command to start the build tool you should leave it running while further developing your app. The build tool automatically detects any relevant file changes using a file watching system and recompiles the necessary changes, restarting your client or server environment as needed. [Hot module replacement](#hot-module-replacement) can optionally be used so you can view and test your changes even quicker. + +### Compiles files with build plugins + +The main function of the Meteor build tool is to run "build plugins". These plugins define different parts of your app build process. Meteor puts heavy emphasis on reducing or removing build configuration files, so you won't see any large build process config files like you would in Gulp or Webpack. The Meteor build process is configured almost entirely through adding and removing packages to your app and putting files in specially named directories. + +For example, to get all of the newest stable ES2015 JavaScript features in your app, you add the [`ecmascript` package](/packages/ecmascript). This package provides support for ES2015 modules, which gives you even more fine-grained control over file load order using ES2015 `import` and `export`. As new Meteor releases add new features to this package you get them for free. + +### Controlling which files to build + +By default Meteor will build certain files as controlled by your application [file structure](/tutorials/application-structure/) and Meteor's default file load order rules. However, you may override the default behavior using `.meteorignore` files, which cause the build system to ignore certain files and directories using the same pattern syntax as `.gitignore` files. These files may appear in any directory of your app or package, specifying rules for the directory tree below them. These `.meteorignore` files are also fully integrated with Meteor's file watching system, so they can be added, removed, or modified during development. + +### Combines and minifies code + +Another important feature of the Meteor build tool is that it automatically concatenates your application asset files, and in production minifies these bundles. This lets you add all of the comments and whitespace you want to your source code and split your code into as many files as necessary, all without worrying about app performance and load times. + +By default, this is enabled by the [`standard-minifier-js`](https://atmospherejs.com/meteor/standard-minifiers-js) and [`standard-minifier-css`](/packages/standard-minifier-css) packages, which use Terser for JavaScript minification. + +**Using SWC Minifier (Meteor 3.3+)**: When you enable the Modern Build Stack with `"modern": true`, Meteor automatically uses the SWC minifier, which is significantly faster than Terser while producing similar or smaller bundle sizes. + +**Using Rspack (Meteor 3.4+)**: When using the Rspack integration, minification is handled by Rspack's built-in SWC minifier, offering the fastest minification with advanced optimizations. + +If you need different minification behavior, you can replace these packages (see [zodern:standard-minifier-js](https://atmospherejs.com/zodern/standard-minifier-js) as an example). + +### Development vs. production + +Running an app in development is all about fast iteration time. All kinds of different parts of your app are handled differently and instrumented to enable better reloads and debugging. In production, the app is reduced to the necessary code and functions just like any standard Node.js app. + +Therefore, you shouldn't run your app in production by executing the `meteor run` command. Instead, follow the directions in [Deploying Meteor Applications](/tutorials/deployment/deployment). If you find an error in production that you suspect is related to minification, you can run the minified version of your app locally for testing with `meteor --production`. + +## Modern Build Stack (Meteor 3.3+) + +Meteor 3.3 introduced the Modern Build Stack, a series of optimizations to make your builds faster and more efficient. Meteor 3.4 expanded this with Rspack integration for even greater performance. + +### Meteor Bundler Optimizations (3.3+) + +The optimized Meteor bundler includes: + +- **SWC Transpilation**: Replace Babel with the faster SWC transpiler for JavaScript/TypeScript compilation +- **SWC Minification**: Use SWC minifier instead of Terser for faster production builds +- **Modern-only Development**: Skip legacy browser builds during development +- **Fast File Watching**: Uses @parcel/watcher for native recursive file watching +- **Enhanced .meteorignore**: Better control over which files are built + +To enable these optimizations, add to your `package.json`: + +```json +{ + "meteor": { + "modern": true + } +} +``` + +Learn more in the [Meteor Bundler Optimizations guide](/about/modern-build-stack/meteor-bundler-optimizations). + +### Rspack Bundler Integration (3.4+) + +Meteor 3.4 introduces optional Rspack integration as a modern, high-performance alternative to the traditional Meteor bundler. Rspack offers significantly faster builds (~5-10x), smaller bundle sizes (20-40% reduction), and access to the modern bundler ecosystem. + +**Quick Start:** + +```bash +# Add the rspack package (included by default in new apps) +meteor add rspack +``` + +**For complete details on Rspack features, configuration, migration guides, and framework integrations, see the [Rspack Bundler Integration guide](/about/modern-build-stack/rspack-bundler-integration).** + +### Comparing Build Options + +| Feature | Meteor Bundler | Meteor + Optimizations | Meteor + Rspack | +|---------|---------------|----------------------|-----------------| +| **Setup** | Default | Add `"modern": true` | Add `rspack` package | +| **Transpiler** | Babel | SWC (with Babel fallback) | SWC via Rspack | +| **Minifier** | Terser | SWC | SWC via Rspack | +| **Build Speed** | Baseline | ~2-3x faster | ~5-10x faster | +| **Bundle Size** | Baseline | Similar | 20-40% smaller | +| **HMR Speed** | Standard | Faster | Fastest | +| **Code Splitting** | Limited | Limited | Full HTTP/2 support | +| **Tree Shaking** | Basic | Basic | Advanced | +| **Ecosystem** | Atmosphere | Atmosphere | Rspack + Atmosphere | +| **Entry Points** | Optional | Optional | Required | +| **Migration** | N/A | Minimal | Moderate | + +## JavaScript transpilation + +These days, the landscape of JavaScript tools and frameworks is constantly shifting, and the language itself is evolving just as rapidly. It's no longer reasonable to wait for web browsers to implement the language features you want to use. Most JavaScript development workflows rely on compiling code to work on the lowest common denominator of environments, while letting you use the newest features in development. Meteor has support for some of the most popular tools out of the box. + +### ES2015+ (recommended) + +The `ecmascript` package (which is installed into all new apps and packages by default, but can be removed), allows support for many ES2015+ features. We recommend using it. You can read more about it in the [Code Style](/tutorials/code-style/code-style) article. + +### SWC (Meteor 3.3+, recommended for performance) + +Starting with Meteor 3.3, you can use SWC as your transpiler for significantly faster builds. SWC is a Rust-based JavaScript/TypeScript compiler that's 20-70x faster than Babel while supporting the same features. + +To enable SWC, add to your `package.json`: + +```json +{ + "meteor": { + "modern": true + } +} +``` + +SWC will handle all transpilation with automatic fallback to Babel for any incompatible code. Learn more in the [Meteor Bundler Optimizations guide](/about/modern-build-stack/meteor-bundler-optimizations). + +### Babel + +Babel is a mature, configurable transpiler which allows you to write code in the latest version of JavaScript even when your supported environments don't support certain features natively. Babel will compile those features down to a supported version. + +Meteor provides a set of appropriate core plugins for each environment (Node.js, modern browsers, and legacy browsers) and React to support most modern JavaScript code practices. In addition, Meteor supports custom `.babelrc` files which allows developers to further customize their Babel configuration to suit their needs (e.g., Stage 0 proposals). + +Developers are encouraged to avoid adding large presets (such as babel-preset-env and babel-preset-react) and instead add specific plugins as needed. You will avoid unnecessary Babel compilation and you'll be less likely to experience plugin ordering issues. + +> **Note**: When using the Modern Build Stack with `"modern": true`, Babel is used as a fallback for any code that SWC cannot handle, ensuring compatibility with all existing Meteor code. + +### CoffeeScript + +While we recommend using ES2015 with the `ecmascript` package as the best development experience for Meteor, everything in the platform is 100% compatible with [CoffeeScript](http://coffeescript.org/) and many people in the Meteor community prefer it. + +All you need to do to use CoffeeScript is add the right Meteor package: + +```bash +meteor add coffeescript +``` + +All code written in CoffeeScript compiles to JavaScript under the hood, and is completely compatible with any code in other packages that is written in JS or ES2015. + +### TypeScript + +[TypeScript](https://www.typescriptlang.org/) is modern JavaScript with optional types and more. Adding types will make your code more readable and less prone to runtime errors. + +TypeScript can be installed with: + +```bash +meteor add typescript +``` + +It is necessary to configure the TypeScript compiler with a `tsconfig.json` file. Here's the one generated by `meteor create --typescript`: + +```json +{ + "compilerOptions": { + "target": "es2018", + "module": "esNext", + "lib": ["esnext", "dom"], + "allowJs": true, + "checkJs": false, + "jsx": "preserve", + "incremental": true, + "noEmit": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": false, + "noFallthroughCasesInSwitch": false, + "baseUrl": ".", + "paths": { + "/*": ["*"] + }, + "moduleResolution": "node", + "resolveJsonModule": true, + "types": ["node", "mocha"], + "esModuleInterop": true, + "preserveSymlinks": true + }, + "exclude": [ + "./.meteor/**", + "./packages/**" + ] +} +``` + +If you want to add TypeScript from the point of project creation, you can run the create command with the --typescript flag: + +```bash +meteor create --typescript name-of-my-new-typescript-app +``` + +#### Conditional imports + +TypeScript does not support nested `import` statements, therefore conditionally importing modules requires you to use the `require` statement. + +To maintain type safety, you can take advantage of TypeScript's import elision and reference the types using the `typeof` keyword. See the [TypeScript handbook article](https://www.typescriptlang.org/docs/handbook/modules.html#optional-module-loading-and-other-advanced-loading-scenarios) for details. + +## Templates and HTML + +Since Meteor uses client-side rendering for your app's UI, all of your HTML code, UI components, and templates need to be compiled to JavaScript. There are a few options at your disposal to write your UI code. + +### Blaze HTML templates + +The aptly named `blaze-html-templates` package that comes with every new Meteor app by default compiles your `.html` files written using [Spacebars](http://blazejs.org/api/spacebars.html) into Blaze-compatible JavaScript code. You can also add `blaze-html-templates` to any of your packages to compile template files located in the package. + +[Read about how to use Blaze and Spacebars in the Blaze documentation.](http://blazejs.org/guide/spacebars.html) + +### Blaze Jade templates + +If you don't like the Spacebars syntax Meteor uses by default and want something more concise, you can give Jade a try by using [`pacreach:jade`](https://atmospherejs.com/pacreach/jade). This package will compile all files in your app with the `.jade` extension into Blaze-compatible code, and can be used side-by-side with `blaze-html-templates` if you want to have some of your code in Spacebars and some in Jade. + +### JSX for React + +If you're building your app's UI with React, currently the most popular way to write your UI components involves JSX, an extension to JavaScript that allows you to type HTML tags that are converted to React DOM elements. JSX code is handled automatically by the `ecmascript` package. + +## CSS processing + +All your CSS style files will be processed using Meteor's default file load order rules along with any import statements and concatenated into a single stylesheet, `merged-stylesheets.css`. In a production build this file is also minified. By default this single stylesheet is injected at the beginning of the HTML `
` section of your application.
+
+However, this can potentially be an issue for some applications that use a third party UI framework, such as Bootstrap, which is loaded from a CDN. This could cause Bootstrap's CSS to come after your CSS and override your user-defined styles.
+
+To get around this problem Meteor supports the use of a pseudo tag `
` section your app will be replaced by a link to this concatenated CSS file. If this pseudo tag isn't used, the CSS file will be placed at the beginning of the `
` section as before. + +### CSS pre-processors + +It's no secret that writing plain CSS can often be a hassle as there's no way to share common CSS code between different selectors or have a consistent color scheme between different elements. CSS compilers, or pre-processors, solve these issues by adding extra features on top of the CSS language like variables, mixins, math, and more, and in some cases also significantly change the syntax of CSS to be easier to read and write. + +Here are three example CSS pre-processors supported by Meteor: + +1. [Sass](http://sass-lang.com/) +2. [Less.js](http://lesscss.org/) +3. [Stylus](https://learnboost.github.io/stylus/) + +They all have their pros and cons, and different people have different preferences. Sass with the SCSS syntax is quite popular as CSS frameworks like Bootstrap have switched to Sass, and the C++ LibSass implementation appears to be faster than some of the other compilers available. + +CSS framework compatibility should be a primary concern when picking a pre-processor, because a framework written with Less won't be compatible with one written in Sass. + +### Source vs. import files + +An important feature shared by all of the available CSS pre-processors is the ability to import files. This lets you split your CSS into smaller pieces, and provides a lot of the same benefits that you get from JavaScript modules: + +1. You can control the load order of files by encoding dependencies through imports, since the load order of CSS matters. +2. You can create reusable CSS "modules" that only have variables and mixins and don't actually generate any CSS. + +In Meteor, each of your `.scss`, `.less`, or `.styl` source files will be one of two types: "source" or "import". + +A "source" file is evaluated eagerly and adds its compiled form to the CSS of the app immediately. + +An "import" file is evaluated only if imported from some other file and can be used to share common mixins and variables between different CSS files in your app. + +Read the documentation for each package listed below to see how to indicate which files are source files vs. imports. + +### Importing styles + +In all three Meteor supported CSS pre-processors you can import other style files from both relative and absolute paths in your app and from both npm and Meteor Atmosphere packages. + +```less +@import '../stylesheets/colors.less'; // a relative path +@import '{}/imports/ui/stylesheets/button.less'; // absolute path with `{}` syntax +``` + +You can also import CSS from a JavaScript file if you have the `ecmascript` package installed: + +```js +import '../stylesheets/styles.css'; +``` + +> When importing CSS from a JavaScript file, that CSS is not bundled with the rest of the CSS processed with the Meteor build tool, but instead is put in your app's `
` tag inside `` after the main concatenated CSS file.
+
+Importing styles from an Atmosphere package using the `{}` package name syntax:
+
+```less
+@import '{my-package:pretty-buttons}/buttons/styles.import.less';
+```
+
+> CSS files in an Atmosphere package are declared with `api.addFiles`, and therefore will be eagerly evaluated, and automatically bundled with all the other CSS in your app.
+
+Importing styles from an npm package using the `{}` syntax:
+
+```less
+@import '{}/node_modules/npm-package-name/button.less';
+```
+
+```js
+import 'npm-package-name/stylesheets/styles.css';
+```
+
+### Sass
+
+The best Sass build plugin for Meteor is [`leonardoventurini:scss`](https://atmospherejs.com/leonardoventurini/scss). An alternative to the previous recommended [`fourseven:scss`](https://atmospherejs.com/fourseven/scss) package.
+
+### Less
+
+Less is maintained as a [Meteor core package called `less`](/packages/less).
+
+### Stylus
+
+The best Stylus build plugin for Meteor is [coagmano:stylus](https://atmospherejs.com/coagmano/stylus).
+
+## PostCSS and Autoprefixer
+
+In addition to CSS pre-processors like Sass, Less, and Stylus, there is now an ecosystem of CSS post-processors. Regardless of which CSS pre-processor you use, a post-processor can give you additional benefits like cross-browser compatibility.
+
+The most popular CSS post-processor right now is [PostCSS](https://github.com/postcss/postcss), which supports a variety of plugins. [Autoprefixer](https://github.com/postcss/autoprefixer) is perhaps the most useful plugin, since it enables you to stop worrying about browser prefixes and compatibility and write standards-compliant CSS. No more copying 5 different statements every time you want a CSS gradient - you can write a standard gradient without any prefixes and Autoprefixer handles it for you.
+
+Meteor automatically runs PostCSS for you once you've configured it. Learn more about enabling it in the docs for [standard-minifier-css](/packages/standard-minifier-css).
+
+## Hot Module Replacement
+
+In Meteor apps, JavaScript, TypeScript, CSS files that are dynamically imported, and many other types of files are converted into JavaScript modules during the build process. Instead of reloading the client after a rebuild, Meteor is able to update the JavaScript modules within the running application that were modified. This reduces the feedback cycle while developing by allowing you to view and test your changes quicker.
+
+### Meteor HMR
+
+Hot module replacement (HMR) can be enabled by adding the [hot-module-replacement](/packages/hot-module-replacement) package to your app:
+
+```bash
+meteor add hot-module-replacement
+```
+
+Many types of JavaScript modules cannot be updated with HMR, so HMR has to be configured to know which modules can be replaced and how to replace them. Most apps never need to do this manually. Instead, you can use integrations that configure HMR for you:
+
+- React components are automatically updated using [React Fast Refresh](https://atmospherejs.com/meteor/react-fast-refresh). This integration is enabled for all Meteor apps that use HMR and a supported React version.
+- Svelte files can be automatically updated with HMR by using the [zodern:melte](https://atmospherejs.com/zodern/melte) compiler package.
+- Vue components can be updated with HMR using [akryum:vue-component](https://atmospherejs.com/akryum/vue-component).
+- Some packages are able to help automatically dispose old versions of modules. For example, [zodern:pure-admin](https://atmospherejs.com/zodern/pure-admin) removes menu items and pages added in the old version of the module.
+
+To further control how HMR applies updates in your app, you can use the [hot API](/packages/hot-module-replacement). This can be used to accept updates for additional types of files, help dispose a module so the old version no longer affects the app (such as stopping Tracker.autorun computations), or creating your own integrations with other view layers or libraries.
+
+If a change was made to the app that cannot be applied with HMR, it reloads the page with hot code push, as is done when HMR is not enabled. It currently only supports app code in the modern client architecture.
+
+### Rspack HMR (3.4+)
+
+When using the [Rspack integration](/about/modern-build-stack/rspack-bundler-integration), you get Rspack's native HMR, which is significantly faster than Meteor's traditional HMR:
+
+- **Faster Updates**: Changes are reflected almost instantly
+- **Persistent State**: Better preservation of application state during updates
+- **Framework Integration**: Automatic support for React Fast Refresh, Vue HMR, Svelte HMR, and more
+- **CSS HMR**: Style changes apply without full page reload (unlike traditional Cordova apps)
+
+**Note**: Blaze HMR is not currently supported with Rspack. Blaze apps will still reload quickly due to Rspack's fast rebuild times (97% reduction), but will perform a full page reload instead of hot module replacement.
+
+To use Rspack HMR, simply add the `rspack` package - HMR is enabled automatically for supported frameworks.
+
+## Build plugins
+
+The most powerful feature of Meteor's build system is the ability to define custom build plugins. If you find yourself writing scripts that mangle one type of file into another, merge multiple files, or something else, it's likely that these scripts would be better implemented as a build plugin. The `ecmascript`, `templating`, and `coffeescript` packages are all implemented as build plugins, so you can replace them with your own versions if you want to!
+
+[Read the documentation about build plugins.](/api/package#build-plugin-api)
+
+### Types of build plugins
+
+There are three types of build plugins supported by Meteor today:
+
+1. **Compiler plugin** - compiles source files (LESS, CoffeeScript) into built output (JS, CSS, asset files, and HTML). Only one compiler plugin can handle a single file extension.
+2. **Minifier plugin** - compiles lots of built CSS or JS files into one or more minified files, for example `standard-minifiers`. Only one minifier can handle each of `js` and `css`.
+3. **Linter plugin** - processes any number of files, and can print lint errors. Multiple linters can process the same files.
+
+### Writing your own build plugin
+
+Writing a build plugin is a very advanced task that only the most advanced Meteor users should get into. The best place to start is to copy a different plugin that is the most similar to what you are trying to do. For example, if you wanted to make a new CSS compiler plugin, you could fork the `less` package; if you wanted to make your own JS transpiler, you could fork `ecmascript`. A good example of a linter is the `jshint` package, and for a minifier you can look at `standard-minifiers-js` and `standard-minifiers-css`.
+
+### Caching
+
+The best way to make your build plugin fast is to use caching anywhere you can - the best way to save time is to do less work! Check out the [documentation about CachingCompiler](/api/package#caching-compiler) to learn more. It's used in all of the above examples, so you can see how to use it by looking at them.
diff --git a/v3-docs/docs/performance/performance-improvement.md b/v3-docs/docs/performance/performance-improvement.md
new file mode 100644
index 0000000000..5de6c40d38
--- /dev/null
+++ b/v3-docs/docs/performance/performance-improvement.md
@@ -0,0 +1,258 @@
+# Performance Improvements
+
+This guide focuses on providing you tips and common practices on how to improve performance of your Meteor app (sometimes also called scaling).
+
+After reading this guide, you'll know:
+
+1. How to use APM for performance monitoring
+2. How to optimize publications and data loading
+3. How to improve Method performance
+4. MongoDB optimization strategies
+5. Scaling approaches for growing applications
+
+It is important to note that at the end of the day Meteor is a Node.js app tied closely to MongoDB, so a lot of the problems you are going to encounter are common to other Node.js and MongoDB apps. Also do note that every app is different so there are unique challenges to each, therefore practices described in this guide should be used as guiding posts rather than absolutes.
+
+## Performance monitoring
+
+Before any optimization can take place we need to know what is our problem. This is where APM (Application Performance Monitor) comes in.
+
+The recommended Meteor-specific APM solution is [Monti APM](https://montiapm.com/). Unlike generic Node.js APM tools, Monti APM understands Meteor's DDP protocol, publications, methods, and livequery observers, giving you insights tailored to your Meteor app.
+
+> **Note:** Galaxy APM (`mdg:meteor-apm-agent`) has been discontinued. If you were using it, migrate to Monti APM which provides the same Meteor-specific monitoring capabilities.
+
+To get started, add the Monti APM agent to your Meteor app:
+
+```bash
+meteor add montiapm:agent
+```
+
+Then configure it with your Monti APM credentials. See the [Monti APM documentation](https://docs.montiapm.com/) for full setup instructions, including [getting started](https://docs.montiapm.com/getting-started) and [dashboard guides](https://docs.montiapm.com/dashboards/jobs-dashboard).
+
+You can also choose other APM tools for Node.js (such as [Datadog](https://www.datadoghq.com/product/apm/) or [Elastic APM](https://github.com/Meteor-Community-Packages/meteor-elastic-apm)), but they will not show you Meteor-specific data like DDP response times, publication performance, and observer reuse metrics.
+
+### Finding issues in APM
+
+APM will start with providing you with an overview of how your app is performing. You can then dive deep into details of publications, methods, errors happening (both on client and server) and more. You will spend a lot of time in the detailed tabs looking for methods and publications to improve and analyzing the impact of your actions.
+
+The process, for example for optimizing methods, will look like this:
+
+1. Go to the detailed view under the Methods tab.
+2. Sort the Methods Breakdown by Response Time.
+3. Click on a method name in the Methods Breakdown. Assess the impact if you improve the selected method.
+4. Look at the response time graph and find a trace.
+5. Improve your method if you feel it is the right moment to do so.
+
+Not every long-performing method has to be improved. Take a look at the following example:
+
+- **methodX** - mean response time 1,515ms, throughput 100.05/min
+- **methodY** - mean response time 34,000ms, throughput 0.03/min
+
+At first glance, the 34 seconds response time can catch your attention, and it may seem that the methodY is more relevant to improvement. But don't ignore the fact that this method is being used only once in a few hours by the system administrators or scheduled cron action.
+
+And now, let's take a look at the methodX. Its response time is evidently lower BUT compared to the frequency of use, it is still high, and without any doubt should be optimized first.
+
+It's also absolutely vital to remember that you shouldn't optimize everything as it goes. The key is to think strategically and match the most critical issues with your product priorities.
+
+## Publications
+
+Publications allow for the most prominent aspect of Meteor: live data. At the same this is the most resource intensive part of a Meteor application.
+
+Under the hood WebSockets are being used with additional abilities provided by DDP.
+
+### Proper use of publications
+
+Since publications can get resource intensive they should be reserved for usage that requires up-to-date, live data or that are changing frequently and you need the users to see that.
+
+You will need to evaluate your app to figure out which situations these are. As a rule of thumb any data that are not required to be live or are not changing frequently can be fetched once via other means and re-fetched as needed, in most cases the re-fetching shouldn't be necessary.
+
+But even before you proceed any further there are a few improvements that you can make here:
+
+- Only get the fields you need
+- Limit the number of documents you send to the client (always set the `limit` option)
+- Ensure that you have set all your indexes
+
+### Methods over publications
+
+The first easiest replacement is to use Meteor methods instead of publications. In this case you can use the existing publication and instead of returning a cursor you will call `.fetchAsync()` and return the actual data. The same performance improvements to get the method work faster apply here, but once called it sends the data and you don't have the overhead of a publication.
+
+```js
+// Instead of a publication
+Meteor.publish('allPosts', function() {
+ return Posts.find({}, { limit: 20 });
+});
+
+// Use a method for one-time data loading
+Meteor.methods({
+ async getPosts() {
+ return await Posts.find({}, { limit: 20 }).fetchAsync();
+ }
+});
+```
+
+What is crucial here is to ensure that your choice of a front-end framework doesn't call the method every time, but only once to load the data or when specifically needed (for example when the data gets updated due to user action or when the user requests it).
+
+### Publication replacements
+
+Using methods has its limitations and there are other tools that you might want to evaluate as a potential replacement:
+
+- [Grapher](https://github.com/cult-of-coders/grapher) is a favorite answer and allows you to easily blend with GraphQL
+- [Apollo GraphQL](https://www.apollographql.com/) has an [integration package](https://atmospherejs.com/meteor/apollo) with Meteor
+- REST APIs for simpler use cases
+
+Do note, that you can mix all of these based on your needs.
+
+### Low observer reuse
+
+Observers are among the key components of Meteor. They take care of observing documents on MongoDB and they notify changes. Creating them is an expensive operation, so you want to make sure that Meteor reuses them as much as possible.
+
+> [Learn more about observers](https://docs.montiapm.com/academy/know-your-observers)
+
+The key for observer reuse is to make sure that the queries requested are identical. This means that user given values should be standardized and so should any dynamic input like time. Publications for users should check if user is signed in first before returning publication and if user is not signed in, then it should instead call `this.ready();`.
+
+```js
+Meteor.publish('userPosts', function() {
+ // Good: Check auth first to enable observer reuse
+ if (!this.userId) {
+ return this.ready();
+ }
+
+ return Posts.find({ userId: this.userId });
+});
+```
+
+> [Learn more on improving observer reuse](https://docs.montiapm.com/academy/improving-cpu-network-usage)
+
+### Redis Oplog
+
+[Redis Oplog](https://atmospherejs.com/cultofcoders/redis-oplog) is a popular solution to Meteor's Oplog tailing (which ensures the reactivity, but has some severe limitations that especially impact performance). Redis Oplog as name suggests uses [Redis](https://redis.io/) to track changes to data that you only need and cache them. This reduces load on the server and database, allows you to track only the data that you want and only publish the changes you need.
+
+## Methods
+
+While methods are listed as one of the possible replacements for publications, they themselves can be made more performant. After all it really depends on what you put inside them and APM will provide you with the necessary insight on which methods are the problem.
+
+### Heavy actions
+
+In general heavy tasks that take a lot of resources or take long and block the server for that time should be taken out and instead be run in its own server that focuses just on running those heavy tasks. This can be another Meteor server or even better something specifically optimized for that given task.
+
+### Reoccurring jobs
+
+Reoccurring jobs are another prime candidate to be taken out into its own application. What this means is that you will have an independent server that is going to be tasked with running the reoccurring jobs and the main application will only add to the list and be recipient of the results, most likely via database results.
+
+### Rate limiting
+
+Rate limit your methods to reduce effectiveness of DDoS attacks and spare your server. This is also a good practice to ensure that you don't accidentally DDoS yourself. For example a user who clicks multiple times on a button that triggers an expensive function.
+
+In this example you should also in general ensure that any button that triggers a server event should be disabled until there is a response from the server that the event has finished.
+
+You can and should rate limit both methods and subscriptions.
+
+> [Learn more about rate limiting](/api/DDPRateLimiter)
+
+## MongoDB
+
+The following section offers some guidance on optimizing performance of your Meteor application when it comes to the database. You can find these and more information in other places that deal with MongoDB performance optimization, like on the [official MongoDB website](https://www.mongodb.com/basics/best-practices). These are all applicable, and you should spend some time researching into them as well. The guide here offers some initial and most common patterns.
+
+### IP whitelisting
+
+If your MongoDB hosting provider allows it, you should make sure that you whitelist the IPs of your application servers. If you don't then your database servers are likely to come under attack from hackers trying to brute force their way in. Besides the security risk this also impacts performance as authentication is not a cheap operation and it will impact performance.
+
+See the [Galaxy container environment guide](https://help.galaxycloud.app/en/article/container-environment-lfd6kh/) on IP whitelisting to get IPs for your Galaxy servers.
+
+### Indexes
+
+While single indexes on one field are helpful on simple query calls, you will most likely have more advanced queries with multiple variables. To cover those you will need to create compound indexes. For example:
+
+```js
+await Statistics.createIndexAsync(
+ {
+ pageId: 1,
+ language: 1,
+ date: 1
+ },
+ { unique: true }
+);
+```
+
+When creating indexes you should sort the variables in ESR (Equality, Sort, Range) style:
+
+1. First you put variables that will be equal to something specific
+2. Second you put variables that sort things
+3. Third variables that provide range for that query
+
+Further you should order these variables in a way that the fields that filter the most should be first.
+
+Make sure that all the indexes are used and remove unused indexes as leaving unused indexes will have negative impact on performance as the database will have to still keep track on all the indexed variables.
+
+### Find strategies
+
+To optimize finds ensure that all queries are indexed. Meaning that any `.find()` variables should be indexed as described above.
+
+All your finds should have a limit on the return so that the database stops going through the data once it has reached the limit, and you only return the limited number of results instead of the whole database.
+
+Beware of queries with `n + 1` issue. For example in a database that has cars and car owners. You don't want to get cars, and then call the database for each car owner, instead you want to use only two queries. One where you get all the cars and second where you get all the owners and then match the data on the front-end.
+
+```js
+// Bad: N+1 queries
+const cars = await Cars.find().fetchAsync();
+for (const car of cars) {
+ const owner = await Owners.findOneAsync({ _id: car.ownerId }); // N queries!
+}
+
+// Good: 2 queries
+const cars = await Cars.find().fetchAsync();
+const ownerIds = cars.map(car => car.ownerId);
+const owners = await Owners.find({ _id: { $in: ownerIds } }).fetchAsync();
+```
+
+Additional tips:
+
+- Check all queries that run longer than 100ms as there might be issues
+- Do not use RegEx for your queries as these queries have to go through all the data to do that match
+- If you still have issues make sure that you read data from secondaries
+
+### Beware of collection hooks
+
+While collection hooks can help in many cases beware of them and make sure that you understand how they work as they might create additional queries that you might not know about. Make sure to review packages that use them so that they won't create additional queries.
+
+### Caching
+
+Once your user base increases you want to invest into query caching like using Redis, Redis Oplog and other. For more complex queries or when you are retrieving data from multiple collections, then you want to use [aggregation](https://www.mongodb.com/docs/manual/aggregation/) and save their results.
+
+## Scaling
+
+### Vertical and horizontal scaling
+
+There are mainly two different ways of scaling: the vertical and horizontal one.
+
+- **Vertical scaling** boils down to adding more resources (CPU/RAM/disk) to your containers
+- **Horizontal scaling** refers to adding more machines or containers to your pool of resources
+
+Horizontal scaling for Meteor projects typically includes running multiple instances of your app on a single container with multiple cores, or running multiple instances on multiple containers.
+
+### Container autoscaling
+
+It is important to be ready for sudden spikes of traffic. While all the other measures mentioned here will help, at a certain point it becomes impossible to support more users on one container and additional containers need to be added to support these users.
+
+Today most hosting solutions offer scaling triggers that you can set to automatically scale up (and down) the number of containers for your app based on things like number of connections, CPU and RAM usage. Galaxy has these as well. Learn more about [setting triggers for scaling on Galaxy](https://help.galaxycloud.app/en/article/scaling-meteor-apps-1wxc9dq/).
+
+Setting this is vital, so that your application can keep on running when you have extra people come and then saves you money by scaling down when the containers are not in use.
+
+When initially setting these pay a close attention to the performance of your app. You need to learn when is the right time to scale your app so it has enough time to spin up new containers before the existing ones get overwhelmed by traffic.
+
+There are other points to pay attention to as well. For example if your app is used by a corporation you might want to setup that on weekdays the minimum number of containers is going to increase just before the start of working hours and then decrease the minimum to 1 for after hours and on weekends.
+
+Usually when you are working on performance issues you will have higher numbers of containers as you optimize your app. It is therefore vital to revisit your scaling settings after each round of improvements to ensure that scaling triggers are properly optimized.
+
+## Packages
+
+During development, it is very tempting to add packages to solve issues or support some features. This should be done carefully and each package should be vetted carefully if it is a good fit for the application.
+
+Besides security and maintenance issues you also want to know which dependencies a given package introduces and as a whole what will be the impact on performance.
+
+## Further reading
+
+- [Monti APM Documentation](https://docs.montiapm.com/)
+- [Monti APM Academy](https://docs.montiapm.com/academy/know-your-observers) - Learn about observers, CPU optimization, and more
+- [MongoDB Best Practices](https://www.mongodb.com/basics/best-practices)
+- [Redis Oplog](https://atmospherejs.com/cultofcoders/redis-oplog)
+- [WebSocket Compression](/performance/websocket-compression)
diff --git a/v3-docs/docs/troubleshooting/hot-code-push.md b/v3-docs/docs/troubleshooting/hot-code-push.md
new file mode 100644
index 0000000000..599544f692
--- /dev/null
+++ b/v3-docs/docs/troubleshooting/hot-code-push.md
@@ -0,0 +1,218 @@
+# Hot Code Push Troubleshooting
+
+Is your Meteor Cordova app not getting the updates you're deploying?
+
+After reading this article, you'll know:
+
+1. The prerequisites to using Hot Code Push
+2. Techniques to diagnose and solve common issues
+3. How to dig deeper if that doesn't solve your issue
+
+This article builds on the [Cordova article](/about/cordova). We recommend reading that first, though we've tried to link back to its relevant sections.
+
+## Prerequisites
+
+Make sure that you have:
+
+- An Android and/or iOS mobile app based on Meteor's Cordova integration
+- The package `hot-code-push` listed in your `.meteor/versions` file
+- **Locally:** Make sure your test device and development device are on the same network
+- **In production:** Make sure the `--server` flag of your `meteor build` command points to the same place as your `ROOT_URL` environment variable (or, on Galaxy, the *site* in `meteor deploy site`)
+
+## Known issues
+
+### Override compatibility versions
+
+Did the app suddenly stop getting new code after you updated Meteor, or you changed plugins?
+
+The client probably logs: `Skipping downloading new version because the Cordova platform version or plugin versions have changed and are potentially incompatible`
+
+Meteor, Cordova and plugins cannot be updated through Hot Code Push. So Meteor by default disables Hot Code Push to app versions that have different versions than the server. This avoids crashing a user's app, for example, when new JS calls a plugin that their app version doesn't yet have.
+
+You can override this behavior by setting the `AUTOUPDATE_VERSION` environment variable. Just make sure you deal with potentially incompatible versions in your JS instead.
+
+### Update your AUTOUPDATE_VERSION
+
+`AUTOUPDATE_VERSION` is an environment variable you can add to your `run` and `deploy` commands:
+
+```bash
+AUTOUPDATE_VERSION=abc meteor deploy example.com
+```
+
+If your app has an `AUTOUPDATE_VERSION` set, make sure you change its value when you want a deploy to update your clients.
+
+### Cordova doesn't hot reload CSS separately
+
+Are you seeing your web app incorporate changes without reload, yet your Cordova app reloads each time?
+
+For CSS-only changes, this is the expected behavior. Browsers update the layout without reload, but in Cordova, any change reloads the whole app.
+
+### Outdated custom reload code and packages
+
+There are several reload packages on Atmosphere, and maybe your app includes some custom reload code. These may have bugs or be outdated.
+
+In particular, when you push an update, does the app reload but use the old code anyway? Probably, the code hasn't been updated to work with newer Meteor versions. We recommend you call `WebAppLocalServer.switchToPendingVersion` before forcing a browser reload.
+
+Alternatively, use the built-in behavior to reload. Instead of, say, `window.location.reload()`, call the `retry` function passed to the `Reload._onMigrate()` callback:
+
+```js
+Reload._onMigrate((retry) => {
+ if (/* not ready */) {
+ window.setTimeout(retry, 5 * 1000); // Check again in 5 seconds
+ return [false];
+ }
+ // ready
+ return [true];
+});
+```
+
+If you use a package that is no longer compatible, consider forking it or opening a PR with the above changes. Alternatively, you can switch to a compatible one such as [`quave:reloader`](https://github.com/quavedev/reloader).
+
+### Avoid hash fragments
+
+Cordova doesn't show the URL bar, but the user is still on some URL or other, which may have a hash (`#`). HCP works better if it doesn't have one.
+
+If you can, remove the hash fragment before the reload.
+
+### Avoid making it download big files
+
+In the client-side logs, you may see HCP fail with errors like:
+
+```
+Error: Error downloading asset: /
+ at http://localhost:12472/plugins/cordova-plugin-meteor-webapp/www/webapp-local-server.js:51:21
+ at Object.callbackFromNative (http://localhost:12472/cordova.js:287:58)
+ at