Refactoring Webpack Series 6 - Configuration Files
I. Basic Usage
The configuration files for webpacks are different. This is because the configuration file for the webpack is a JavaScript file, in which an object for the webpack configuration is exported, and then the webpack is processed according to the properties defined by the configuration.
The conclusion of this article is that the configuration of a webpack can have many different styles and styles. The key is to maintain and understand these configurations easily and consistently within the team. This article is based on webpack@5 Version for instructions.
a. Basic configuration
const path = require('path'); module.exports = { mode: 'development', entry: './foo.js', output: { path: path.resolve(__dirname,'dist'), filename: 'foo.bundle.js' } }
b. Different profiles
In the course of a general development project, development and production environments are distinguished, so the corresponding configuration files for the webpack should also be separated:
// package.json "scripts": { "build": "webpack --config webpack.prod.config.js", "dev": "webpack --config webpack.dev.config.js" }
c. Other configurations
There are many options for a complete configuration file for webpack, so let's get to know it all:
const path = require('path'); module.exports = { mode: "production", //"production" | "development" | "none" // Choosing a different mode tells the webpack to use its built-in optimizations accordingly. entry: "./app/entry.js", // string | object | array // Default to. / src, where the application starts executing and the webpack begins packaging output: { // Options for webpack output path: path.resolve(__dirname, "dist"), // The destination path for all output files must be absolute (using the path module of nodejs) filename: "[name].js", // string(default) // File name template for entry chunk publicPath: "/assets/", // string // Output Parse File Directory, url relative to html page library: { type: "umd", // Common Module Definition // Type of export Library name: "MyLibrary", // string | string[] // Name of export Library }, uniqueName: "my-application", // The unique name of this build to avoid conflicts with other builds in the same HTML name: "my-config", // The name of the configuration, shown in the output }, module: { // Module configuration related rules: [ // Module Rules (Configure loader, Parser Options) { // Matching Conditions: test: /\.jsx?$/, include: [ path.resolve(__dirname, "app") ], exclude: [ path.resolve(__dirname, "app/demo-files") ] // These are matching criteria, each accepting a regular expression or string //Testing and containment have the same behavior and must match //Exclusion does not match (prior to testing and inclusion) //Best practices: //- Use RegExp only in tests and file name matching //-Use absolute path arrays to match full paths in include and exclude //-Avoid exclusion as much as possible and prefer to include //Each condition can also receive objects with an "and", "or" or "not" attribute //This is a series of conditions. issuer: /\.css$/, issuer: path.resolve(__dirname, "app"), issuer: { and: [ /\.css$/, path.resolve(__dirname, "app") ] }, issuer: { or: [ /\.css$/, path.resolve(__dirname, "app") ] }, issuer: { not: [ /\.css$/ ] }, issuer: [ /\.css$/, path.resolve(__dirname, "app") ], // like "or" // Execute Actions: // Single loader: loader: "babel-loader", // Applied loader, relative to context resolution // Configuration options for loader options: { presets: ["es2015"] }, // Apply options corresponding to multiple composite loaders and loaders use: [ "htmllint-loader", { loader: "htmllint-loader", options: { //... } } ], type: "javascript/auto", // Specify the type of module }, { oneOf: [ // ...(rules) ] // Use only one set of rules }, { // ... (conditions) rules: [ // ...(rules) ] // Use all these nested rules (combined with conditions of use) } ] }, resolve: { // Options for parsing module requests // Module resolution not applicable to loader modules: ["node_modules",path.resolve(__dirname, "app")], // Find the directory of modules (in array order) extensions: [".js",".json",".jsx",".css"], // Extensions used alias: { // List of module name aliases // Aliases are imported relative to the current context "module": "new-module", // Alias:'module'- >'new-module' and'module/path/file'- >'new-module/path/file' "only-module$": "new-module", // Alias "only-module" -> "new-module", but does not match "only-module/path/file" -> "new-module/path/file" "module": path.resolve(__dirname, "app/third/module.js"), // Aliases "module" -> "/app/third/module.js" and "module/file" caused errors "module": path.resolve(__dirname, "app/third"), // Aliases are "module" ->"/ app/third"and "module/file" ->"/ app/third/file" [path.resolve(__dirname, "app/module.js")]: path.resolve(__dirname, "app/alternative-module.js"), // Alias "/app/module.js" ->"/app/alternative module.js" } }, performance: {}, // Not available devtool: "source-map", // Enhance debugging capabilities by providing very detailed meta-information of source maps to browser debugging tools // But at the expense of build speed! context: __dirname, // string (absolute path!) // Home directory of webpack // entry and module.rules.loader options are resolved relative to this directory target: 'web', // Since JavaScript can write both server-side and browser-side code, the webpack provides a variety of deployment target s, with the web representing the browser-side and the default being browserlist devServer: { proxy: {}, // agent static: path.join(__dirname, 'public'), //boolean | string | array | object, static file location compress: true, // Whether to turn on gzip compression historyApiFallback: true, // Don't know how to use it hot: true, // Hot Update https: false, }, plugins: [], //Plug-in unit optimization: { // Optimize Options chunkIds: "size", // How to generate an id for a module, telling the webpack which algorithm to use when choosing a module id moduleIds: "size", // Module id generation method that tells webpack which algorithm to use when selecting a module id mangleExports: "size", // Rename the export name to a shorter name minimize: true, // Minimize Output Files minimizer: [new CssMinimizer(), "..."], // Minimum value for output file splitChunks: { cacheGroups: { "my-name": { // Define module groups with specific properties test: /\.sass$/, type: "css/mini-extract" } } } } }
2. Export Method
In addition to exporting individual configurations, there are several ways to export configurations that meet more requirements.
A. Export as a function
The distinction between development and production environments can also be handled by exporting to a function that contains two parameters:
- Parameter 1 is the environment
- Parameter 2 is the configuration item passed to the webpack
module.exports = funtion(env, argv) { return { mode: env.production ? 'production':'development', devtool: env.production ? 'source-map' : 'eval', plugins: [ new TerserPlugin({ terserOptions: { compress: argv.mode === 'production' } }) ] } }
b. Export to Promise
When a configuration variable needs to be loaded asynchronously, the webpack executes the function, exports a configuration file, and returns a Promise. Webpack supports using Promise.all([your promise]) exports multiple promises:
module.exports = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ entry: './app.js', // ... }) }, 5000) }) }
c. Exporting multiple configurations
In addition to exporting a single configuration object/function, you may also need to export multiple configurations ( webpack@3 Above). When the webpack runs, all configuration items are built, such as libraries built with multiple targets such as AMD and CommonJS:
module.exports = [ { output: { filename: './dist-amd.js', libraryTarget: 'amd' }, name: 'amd', entry: './app.js', mode: 'production' }, { output: { filename: './dist-commonjs.js', libraryTarget: 'commonjs', }, name: 'commonjs', entry: './app.js', mode: 'production' } ]
Note: If you only pass in a--config-name name name identity, the webpack will only build the specified configuration item.
d.dependencies (based on c)
In case one of your configurations depends on the output of another, you can specify a dependencies list using a dependencies list:
module.exports = [ { name: 'client', target: 'web', // ... }, { name: 'server', target: 'node', dependencies: ['client'], }, ]
e.parallelism (based on c)
If you have exported multiple configurations, you can use the parallelism option in the configuration to specify the maximum number of concurrencies compiled. ( webpack@5.22 Above)
module.exports = [ { //config-1 }, { //config-2 }, ]; module.exports.parallelism = 1;
3. Use other languages
Webpack supports writing configuration files in a variety of programming languages and data description formats. You can find a list of currently supported file types in node-interpret, which the webpack can handle.
a.TypeScript
npm install --save-dev typescript ts-node @types/node @types/webpack // If you use webpack-dev-server, you also need to install the following dependencies npm install --save-dev @types/webpack-dev-server
Once the installation is complete, you can start writing the configuration file, as shown in the following example:
// webpack.config.ts import * as path from 'path'; import * as webpack from 'webpack'; // If you need to configure devServer, you need to introduce the following import 'webpack-dev-server' const config: webpack.Configuration = { mode: 'production', entry: './foo.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'foo.bundle.js' } } export default config;
This example requires typescript version 2.7 and above, and in tsconfig. Two configuration items, esModuleInterop and allowSyntheticDefaultImports, are added to the compilerOptions of the JSON file.
It is important to note that you need to ensure tsconfig. The value of the module option in json's compilerOptions is commonjs, otherwise the webpack will fail and error because ts-node does not support module specifications other than commonjs.
There are three ways you can set up a module:
- Direct tsconfig.json file
- Modify tsconfig.json and add ts-node settings
- tsconfig-paths
The first way is to open your tsconfig.json file, find the configuration for compilerOptions, and then set the target and module options to "ES5" and "CommonJs" (you can also not display the configuration for writing modules when target is set to ES5).
// tsconfig.json { "compilerOptions": { "target": "ES5", "module": "ESNext" } }
The second method is to add the ts-node settings:
You can keep the "module" configuration for tsc: "ESNext" and set an override for ts-node if you are using a webpack or other build tool:
// tsconfig.json { "compilerOptions": { "module": "ESNext", }, "ts-node": { "compilerOptions": { "module": "CommonJS" } } }
The third way is to install the npm package tsconfig-paths first, as follows:
npm install --save-dev tsconfig-paths
After installation, you can create a separate TypeScript configuration file for the webpack configuration as follows:
// tsconfig-for-webpack-config.json { "compilerOptions": { "module": "commonjs", "target": "es5", "esModuleInterop": true } }
ts-node can use the environment variable process provided by tsconfig-paths. Env. TS_ NODE_ PROJECT to find tsconfig.json file path.
Process. Env. TS_ NODE_ The PROJECT variable is set as follows:
// package:json { "scripts": { "build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\"webpack" } }
The cross-env was added because we are using TS_directly NODE_ PROJECT encountered feedback from unrecognized command error "TS_NODE_PROJECT", which was resolved after adding cross-env.
b.CoffeeScript
Similar to Typescript, you need to install its dependencies before using CoffeeScript, as follows:
npm install --save-dev coffeescript
Then write a configuration file:
// webpack.config.coffee HtmlWebpackPlugin = require('html-webpack-plugin') webpack = require('webpack') path = require('path') config = mode: 'production' entry: './path/to/my/entry/file.js' output: path: path.resolve(__dirname, 'dist') filename: 'my-first-bundle.js' module: rules: [{ test: /\.(js|jsx)$/ use: 'babel-loader' }] plugins: [ new HtmlWebpackPlugin(template: './src/index.html') ] module.exports = config
c.Babel and JSX
First, as with the above two approaches, you need to install some necessary dependencies, as shown below:
npm install --save-dev babel-register jsxobj babel-preset-es2015
To write. babelrc profile:
{ "presets": ["es2015"] }
Write a webpack configuration file:
// webpack.config.babel.js import jsxobj from 'jsxobj' // Example of plug-in introduction const CustomPlugin = (config) => ({ ...config, name: 'custom-plugin' }) export default ( <webpack target="web" watch mode="production"> <entry path="src/index.js" /> <resolve> <alias {...{ react: 'preact-compat', 'react-dom': 'preact-compat' }} /> </resolve> <plugins> <CustomPlugin foo="bar" /> </plugins> </webpack> )
If you use Babel elsewhere and the modules value is set to false, you must maintain two copies. babelrc files, or you can replace the import jsxobj from'jsxobj'in the example above with const jsxobj = require('jsxobj'). And replace the new export syntax with module.exports, because node does not yet support module syntax for ES6.
4. Notes
- The webpack fully follows the CommonJS module specification
- You can import other files through require()
- Tool functions that can be downloaded using npm through require()
- You can write with ternary operators
- You can assign value s using constants or variables
- Write and execute functions to generate partial configurations
- Configuration files should not be too long and need to be split up if necessary, such as distinguishing environments
This is the end of the article. Interested partners appreciate every point of interest.