webpack: Detailed explanation of the use of some important APIs for entry and output

context

Before talking about entry and output, we need to talk about context, which is the context object.

Webpack will use context as the root directory when looking for files with relative paths. Context defaults to the current working directory where Webpack is started. If you want to change the default configuration of context, you can set it in the configuration file like this:

module.exports = {
    
    
  context: path.resolve(__dirname, 'app')
}

The reason why context is introduced here first is because the path of Entry and the paths of its dependent modules may be described by paths relative to context, and context will affect the real files pointed to by these relative paths.

entry

single entrance

module.exports = {
    
    
  entry: {
    
    
    main: './path/to/my/entry/file.js',
  },
};
// 简写
module.exports = {
    
    
  entry: './path/to/my/entry/file.js',
};

So you can see that when we use the default configuration, that is, the output does not specify the name of the output, then the packaged file is main.js, because the default here at our entrance is main.

multiple entrances

Two ways of writing

module.exports = {
    
    
  entry: ['./src/file_1.js', './src/file_2.js']
};

module.exports = {
    
    
  entry: {
    
    
    app: './src/app.js',
    adminApp: './src/adminApp.js',
  },
};

The advantage of object writing is that it is highly scalable and can be split and then merged using specialized tools (such as webpack-merge).

entry related API

  • dependOn: The entry that the current entry depends on. They must be loaded before this entry is loaded.
  • filename: Specify the file name to be output.
  • import: module to be loaded at startup.
  • library: Specify the library option to build a library for the current entry.
  • runtime: The name of the runtime chunk. If set, a new runtime chunk will be created. It can be set to false after webpack 5.43.0 to avoid a new runtime chunk.
  • publicPath: Specifies a public URL address for the entry's output files when they are referenced in the browser. Please see output.publicPath.

These APIs are rarely used, and they are mainly used for code splitting. We generally use optimization.splitChunks to do code splitting. You can read my article

Example 1

module.exports = {
    
    
  //...
  entry: {
    
    
    home: './home.js',
    shared: ['react', 'react-dom', 'redux', 'react-redux'],
    catalog: {
    
    
      import: './catalog.js',
      filename: 'pages/catalog.js',
      dependOn: 'shared',
      chunkLoading: false, // Disable chunks that are loaded on demand and put everything in the main chunk.
    },
    personal: {
    
    
      import: './personal.js',
      filename: 'pages/personal.js',
      dependOn: 'shared',
      chunkLoading: 'jsonp',
      asyncChunks: true, // Create async chunks that are loaded on demand.
      layer: 'name of layer', // set the layer for an entry point
    },
  },
};

Example 2

Using dependOn, the app chunk will not contain modules owned by react-vendors.

module.exports = {
    
    
  //...
  entry: {
    
    
    app: {
    
     import: './app.js', dependOn: 'react-vendors' },
    'react-vendors': ['react', 'react-dom', 'prop-types'],
  },
};

The dependOn option can also be an array of strings:

module.exports = {
    
    
  //...
  entry: {
    
    
    moment: {
    
     import: 'moment-mini', runtime: 'runtime' },
    reactvendors: {
    
     import: ['react', 'react-dom'], runtime: 'runtime' },
    testapp: {
    
    
      import: './wwwroot/component/TestApp.tsx',
      dependOn: ['reactvendors', 'moment'],
    },
  },
};

Example 3

Load dynamic entry

// 同步
module.exports = {
    
    
  //...
  entry: () => './demo',
};

// 异步
module.exports = {
    
    
  //...
  entry: () => new Promise((resolve) => resolve(['./demo', './demo2'])),
};

// 异步接口加载
module.exports = {
    
    
  entry() {
    
    
    return fetchPathsFromSomeExternalSource(); // 返回一个会被用像 ['src/main-layout.js', 'src/admin-layout.js'] 的东西 resolve 的 promise
  },
};

output

output.assetModuleFilename

Static resource file name, such as pictures, fonts, icons, etc.
Default: string = '[hash][ext][query]'
You can use:[name], [file], [query], [fragment], [base] 与 [path]

const path = require('path');

module.exports = {
    
    
  entry: './src/index.js',
  output: {
    
    
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
   assetModuleFilename: 'images/[hash][ext][query]'
  },
  module: {
    
    
    rules: [
      {
    
    
        test: /\.png/,
        type: 'asset/resource'
      }
    ]
  },
};

As a digression, resource names are generally not changed in output, but here

const path = require('path');

module.exports = {
    
    
 entry: './src/index.js',
 output: {
    
    
   filename: 'main.js',
   path: path.resolve(__dirname, 'dist'),
   assetModuleFilename: 'images/[hash][ext][query]'
 },
 module: {
    
    
   rules: [
     {
    
    
       test: /\.png/,
       type: 'asset/resource'
    }
    },
    {
    
    
      test: /\.html/,
      type: 'asset/resource',
      // 这里
      generator: {
    
    
        filename: 'static/[hash][ext][query]'
      }
    }
   ]
 },
};

output.chunkFilename

The output chunk file name.

module.exports = {
    
    
  //...
  output: {
    
    
    chunkFilename: (pathData) => {
    
    
      return pathData.chunk.name === 'main' ? '[name].js' : '[name]/[name].js';
    },
  },
};

Generally we don’t use this setting, but use optimization.splitChunks to do it. You can read my article

output.clean【5.20.0+ version support】

Clearing packaged resources has the same function as the CleanWebpackPlugin plug-in.

module.exports = {
    
    
  //...
  output: {
    
    
    clean: true, // 在生成文件之前清空 output 目录
  },
};

output.filename【Important】

The name of each output bundle that will be written to the directory specified by the output.path option.

module.exports = {
    
    
  //...
  output: {
    
    
    filename: 'bundle.js',
  },
};

module.exports = {
    
    
  //...
  output: {
    
    
    filename: '[name].bundle.js',
  },
};

module.exports = {
    
    
  //...
  output: {
    
    
    filename: (pathData) => {
    
    
      return pathData.chunk.name === 'main' ? '[name].js' : '[name]/[name].js';
    },
  },
};

id Chunk's unique identifier, starting from 0
name Chunk's name
hash Hash value of Chunk's unique identifier
chunkhash Hash value of chunk content.
The length of hash and chunkhash can be specified. [hash:8] represents an 8-bit Hash value. The default is 20 bits.

output.globalObject

Default: string = 'self'
When the output is a library, especially when libraryTarget is 'umd', this option determines which global object is used to mount the library.

module.exports = {
    
    
  // ...
  output: {
    
    
    library: 'myLib',
    libraryTarget: 'umd',
    filename: 'myLib.js',
    globalObject: 'this',
  },
};

output.library【Important】

Export a library to export for your entry.

module.exports = {
    
    
  // …
  entry: './src/index.js',
  output: {
    
    
    library: 'MyLibrary',
  },
};

Example:
Use the above configuration to package the file

export function hello(name) {
    
    
  console.log(`hello ${
      
      name}`);
}

After packaging, you can use it like this

<script src="https://example.org/path/to/my-library.js"></script>
<script>
  MyLibrary.hello('webpack');
</script>

output.library.name

Same as above

output.library.type [Important]

How the configuration library is exposed.
The default types include 'var', 'module', 'assign', 'assign-properties', 'this', 'window', 'self', 'global', 'commonjs', 'commonjs2', 'commonjs-module' , 'commonjs-static', 'amd', 'amd-require', 'umd', 'umd2', 'jsonp' and 'system'. In addition, it can also be added through plugins.

Example

module.exports = {
    
    
  // …
  output: {
    
    
    library: {
    
    
      name: 'MyLibrary',
      type: 'var',
    },
  },
};

var MyLibrary = _entry_return_;
// 在加载了 `MyLibrary` 的单独脚本中
MyLibrary.doSomething();
module.exports = {
    
    
  // …
  output: {
    
    
    library: {
    
    
      name: 'MyLibrary',
      type: 'assign',
    },
  },
};

// 直接赋值给MyLibrary,不管有没有定义,慎用
MyLibrary = _entry_return_;
// 使用assign-properties更安全:如果 MyLibrary 已经存在的话,它将被重用
module.exports = {
    
    
  // …
  output: {
    
    
    library: {
    
    
      name: 'MyLibrary',
      type: 'this',
    },
  },
};

this['MyLibrary'] = _entry_return_;

// 在一个单独的脚本中
this.MyLibrary.doSomething();
MyLibrary.doSomething(); // 如果 `this` 为 window 对象
module.exports = {
    
    
  // …
  output: {
    
    
    library: {
    
    
      name: 'MyLibrary',
      type: 'window',
    },
  },
};

window['MyLibrary'] = _entry_return_;

window.MyLibrary.doSomething();
module.exports = {
    
    
  // …
  output: {
    
    
    library: {
    
    
      name: 'MyLibrary',
      type: 'global',
    },
  },
};

global['MyLibrary'] = _entry_return_;

global.MyLibrary.doSomething();
module.exports = {
    
    
  // …
  output: {
    
    
    library: {
    
    
      name: 'MyLibrary',
      type: 'commonjs',
    },
  },
};

exports['MyLibrary'] = _entry_return_;

require('MyLibrary').doSomething();
module.exports = {
    
    
  // …
  // 试验性质的模块要加上这个
  experiments: {
    
    
    outputModule: true,
  },
  output: {
    
    
    library: {
    
    
      // do not specify a `name` here,输出 ES 模块。
      type: 'module',
    },
  },
};

module.exports = {
    
    
  // …
  output: {
    
    
    library: {
    
    
      // note there's no `name` here
      type: 'commonjs2',
    },
  },
};

module.exports = _entry_return_;

require('MyLibrary').doSomething();
...还有amd、umd,用的都比较少,我们正常一般不指定,所以我们导出的库支持所有导入方式,或者我们使用esmodule也不错

output.library.auxiliaryComment

Comment on the different export methods in the packaged file

module.exports = {
    
    
  // …
  mode: 'development',
  output: {
    
    
    library: {
    
    
      name: 'MyLibrary',
      type: 'umd',
      auxiliaryComment: {
    
    
        root: 'Root Comment',
        commonjs: 'CommonJS Comment',
        commonjs2: 'CommonJS2 Comment',
        amd: 'AMD Comment',
      },
    },
  },
};

output.path【Important】

defaultstring = path.join(process.cwd(), 'dist')

const path = require('path');

module.exports = {
    
    
  //...
  output: {
    
    
    path: path.resolve(__dirname, 'dist/assets'),
  },
};

output.publicPath

Generally use the publicPath of the root directory

module.exports = {
    
    
  //...
  output: {
    
    
    // One of the below
    publicPath: 'auto', // It automatically determines the public path from either `import.meta.url`, `document.currentScript`, `<script />` or `self.location`.
    publicPath: 'https://cdn.example.com/assets/', // CDN(总是 HTTPS 协议)
    publicPath: '//cdn.example.com/assets/', // CDN(协议相同)
    publicPath: '/assets/', // 相对于服务(server-relative)
    publicPath: 'assets/', // 相对于 HTML 页面
    publicPath: '../assets/', // 相对于 HTML 页面
    publicPath: '', // 相对于 HTML 页面(目录相同)
  },
};
const getPublicPath = () => {
    
    
  if (process.env.NODE_ENV === "development") {
    
    
    return "/project_name";
  } else {
    
    
    return `//cdn.xxx.com/repo/project_name/dist/`;
  }
};
publicPath: getPublicPath()

Guess you like

Origin blog.csdn.net/weixin_43972437/article/details/133163433