webpack入门学习
概念
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
入口(entry)
入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。通过配置 entry 属性,来指定一个入口起点(或多个入口起点)
单个入口(简写)语法
const config = {entry: {main: './path/to/my/entry/file.js'}
};
多入口
const config = {entry: {pageOne: './src/pageOne/index.js',pageTwo: './src/pageTwo/index.js',pageThree: './src/pageThree/index.js'}
};
动态入口
entry: () => './demo'
entry: () => new Promise((resolve) => resolve(['./demo', './demo2']))
出口(output)
output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个 output 字段,来配置这些处理过程
在 webpack 中配置 output 属性的最低要求是,将它的值设置为一个对象,包括以下两点:
- filename 用于输出文件的文件名。
- 目标输出目录 path 的绝对路径。
const config = {output: {filename: 'bundle.js',path: '/home/proj/public/assets'}
};module.exports = config;
多个入口起点
如果配置创建了多个单独的 “chunk”(例如,使用多个入口起点或使用像 CommonsChunkPlugin 这样的插件),则应该使用占位符(substitutions)来确保每个文件具有唯一的名称
{entry: {app: './src/app.js',search: './src/search.js'},output: {filename: '[name].js',path: __dirname + '/dist',publicPath: "https://cdn.example.com/assets/"//生产环境配置前置路劲,项目打包后会拼接该路劲}
}
高级进阶
以下是使用 CDN 和资源 hash 的复杂示例:
output: {path: "/home/proj/cdn/assets/[hash]",publicPath: "http://cdn.example.com/assets/[hash]/"
}
在编译时不知道最终输出文件的 publicPath 的情况下,publicPath 可以留空,并且在入口起点文件运行时动态设置。如果你在编译时不知道 publicPath,你可以先忽略它,并且在入口起点设置 webpack_public_path。
__webpack_public_path__ = myRuntimePublicPath
加载器(loader)
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理,类似gulp中的task(任务)。
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。
在 webpack 配置中定义 loader 时,要定义在 module.rules 中,而不是 rules。
在 webpack 的配置中 loader 有两个目标:
- test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
- use 属性,表示进行转换时,应该使用哪个loader。
loader 特性
-
loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的JavaScript。
-
loader 可以是同步的,也可以是异步的
-
loader 运行在 Node.js中,并且能够执行任何可能的操作。
-
loader 接收查询参数。用于对 loader 传递配置。
-
loader 也能够使用 options对象进行配置。
-
除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在
-
package.json 里定义一个 loader 字段。
-
插件(plugin)可以为 loader 带来更多特性。
-
loader 能够产生额外的任意文件。
解析 loader
loader 遵循标准的模块解析。多数情况下,loader 将从模块路径(通常将模块路径认为是 npm install, node_modules)解析。
loader 模块需要导出为一个函数,并且使用 Node.js 兼容的 JavaScript 编写。通常使用 npm 进行管理,但是也可以将自定义 loader 作为应用程序中的文件。按照约定,loader 通常被命名为 xxx-loader(例如 json-loader)
插件(plugins)
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。
想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例。
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
const path = require('path'); // nodejs路径解析模块const config = {entry: './path/to/my/entry/file.js',output: {path: path.resolve(__dirname, 'dist'),filename: 'my-first-webpack.bundle.js'},module: {rules: [{ test: /\.txt$/, use: 'raw-loader' }]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})]
};module.exports = config;
模式
通过选择 development 或 production 之中的一个,来设置 mode 参数,你可以启用相应模式下的 webpack 内置的优化
module.exports = {mode: 'production'
};
webpack配置
const path = require('path');module.exports = {mode: "production", // "production" | "development" | "none"mode: "production", // enable many optimizations for production buildsmode: "development", // enabled useful tools for developmentmode: "none", // no defaults// Chosen mode tells webpack to use its built-in optimizations accordingly.entry: "./app/entry", // 如果传入一个字符串或字符串数组,chunk 会被命名为 main。如果传入一个对象,则每个键(key)会是 chunk 的名称,该值描述了 chunk 的入口起点。entry: ["./app/entry1", "./app/entry2"],entry: {a: "./app/entry-a",b: ["./app/entry-b1", "./app/entry-b2"]},// 这里应用程序开始执行// webpack 开始打包output: {// webpack 如何输出结果的相关选项path: path.resolve(__dirname, "dist"), // string// 所有输出文件的目标路径// 必须是绝对路径(使用 Node.js 的 path 模块)filename: "bundle.js", // stringfilename: "[name].js", // 用于多个入口点(entry point)(出口点?)filename: "[chunkhash].js", // 用于长效缓存// 「入口分块(entry chunk)」的文件名模板(出口分块?)publicPath: "/assets/", // stringpublicPath: "",publicPath: "https://cdn.example.com/",// 输出解析文件的目录,url 相对于 HTML 页面library: "MyLibrary", // string,// 导出库(exported library)的名称libraryTarget: "umd", // 通用模块定义libraryTarget: "umd2", // 通用模块定义libraryTarget: "commonjs2", // exported with module.exportslibraryTarget: "commonjs-module", // 使用 module.exports 导出libraryTarget: "commonjs", // 作为 exports 的属性导出libraryTarget: "amd", // 使用 AMD 定义方法来定义libraryTarget: "this", // 在 this 上设置属性libraryTarget: "var", // 变量定义于根作用域下libraryTarget: "assign", // 盲分配(blind assignment)libraryTarget: "window", // 在 window 对象上设置属性libraryTarget: "global", // property set to global objectlibraryTarget: "jsonp", // jsonp wrapper// 导出库(exported library)的类型/* 高级输出配置(点击显示) */pathinfo: true, // boolean// 在生成代码时,引入相关的模块、导出、请求等有帮助的路径信息。chunkFilename: "[id].js",chunkFilename: "[chunkhash].js", // 长效缓存(/guides/caching)// 「附加分块(additional chunk)」的文件名模板jsonpFunction: "myWebpackJsonp", // string// 用于加载分块的 JSONP 函数名sourceMapFilename: "[file].map", // stringsourceMapFilename: "sourcemaps/[file].map", // string// 「source map 位置」的文件名模板devtoolModuleFilenameTemplate: "webpack:///[resource-path]", // string// 「devtool 中模块」的文件名模板devtoolFallbackModuleFilenameTemplate: "webpack:///[resource-path]?[hash]", // string// 「devtool 中模块」的文件名模板(用于冲突)umdNamedDefine: true, // boolean// 在 UMD 库中使用命名的 AMD 模块crossOriginLoading: "use-credentials", // 枚举crossOriginLoading: "anonymous",crossOriginLoading: false,// 指定运行时如何发出跨域请求问题/* 专家级输出配置(自行承担风险) */},module: {// 关于模块配置rules: [// 模块规则(配置 loader、解析器等选项){test: /\.jsx?$/,include: [path.resolve(__dirname, "app")],exclude: [path.resolve(__dirname, "app/demo-files")],// 这里是匹配条件,每个选项都接收一个正则表达式或字符串// test 和 include 具有相同的作用,都是必须匹配选项// exclude 是必不匹配选项(优先于 test 和 include)// 最佳实践:// - 只在 test 和 文件名匹配 中使用正则表达式// - 在 include 和 exclude 中使用绝对路径数组// - 尽量避免 exclude,更倾向于使用 includeissuer: { test, include, exclude },// issuer 条件(导入源)enforce: "pre",enforce: "post",// 标识应用这些规则,即使规则覆盖(高级选项)loader: "babel-loader",// 应该应用的 loader,它相对上下文解析// 为了更清晰,`-loader` 后缀在 webpack 2 中不再是可选的// 查看 webpack 1 升级指南。options: {presets: ["es2015"]},// loader 的可选项},{test: /\.html$/,test: "\.html$"use: [// 应用多个 loader 和选项"htmllint-loader",{loader: "html-loader",options: {/* ... */}}]},{ oneOf: [ /* rules */ ] },// 只使用这些嵌套规则之一{ rules: [ /* rules */ ] },// 使用所有这些嵌套规则(合并可用条件){ resource: { and: [ /* 条件 */ ] } },// 仅当所有条件都匹配时才匹配{ resource: { or: [ /* 条件 */ ] } },{ resource: [ /* 条件 */ ] },// 任意条件匹配时匹配(默认为数组){ resource: { not: /* 条件 */ } }// 条件不匹配时匹配],/* 高级模块配置(点击展示) */noParse: [/special-library\.js$/],// 不解析这里的模块unknownContextRequest: ".",unknownContextRecursive: true,unknownContextRegExp: /^\.\/.*$/,unknownContextCritical: true,exprContextRequest: ".",exprContextRegExp: /^\.\/.*$/,exprContextRecursive: true,exprContextCritical: true,wrappedContextRegExp: /.*/,wrappedContextRecursive: true,wrappedContextCritical: false,// specifies default behavior for dynamic requests},resolve: {// 解析模块请求的选项// (不适用于对 loader 解析)modules: ["node_modules",path.resolve(__dirname, "app")],// 用于查找模块的目录extensions: [".js", ".json", ".jsx", ".css"],// 使用的扩展名alias: {// 模块别名列表"module": "new-module",// 起别名:"module" -> "new-module" 和 "module/path/file" -> "new-module/path/file""only-module$": "new-module",// 起别名 "only-module" -> "new-module",但不匹配 "only-module/path/file" -> "new-module/path/file""module": path.resolve(__dirname, "app/third/module.js"),// 起别名 "module" -> "./app/third/module.js" 和 "module/file" 会导致错误// 模块别名相对于当前上下文导入},/* 可供选择的别名语法(点击展示) */alias: [{name: "module",// 旧的请求alias: "new-module",// 新的请求onlyModule: true// 如果为 true,只有 "module" 是别名// 如果为 false,"module/inner/path" 也是别名}],/* 高级解析选项(点击展示) */symlinks: true,// 遵循符号链接(symlinks)到新位置descriptionFiles: ["package.json"],// 从 package 描述中读取的文件mainFields: ["main"],// 从描述文件中读取的属性// 当请求文件夹时aliasFields: ["browser"],// 从描述文件中读取的属性// 以对此 package 的请求起别名enforceExtension: false,// 如果为 true,请求必不包括扩展名// 如果为 false,请求可以包括扩展名moduleExtensions: ["-module"],enforceModuleExtension: false,// 类似 extensions/enforceExtension,但是用模块名替换文件unsafeCache: true,unsafeCache: {},// 为解析的请求启用缓存// 这是不安全,因为文件夹结构可能会改动// 但是性能改善是很大的cachePredicate: (path, request) => true,// predicate function which selects requests for cachingplugins: [// ...]// 应用于解析器的附加插件},performance: {hints: "warning", // 枚举hints: "error", // 性能提示中抛出错误hints: false, // 关闭性能提示maxAssetSize: 200000, // 整数类型(以字节为单位)maxEntrypointSize: 400000, // 整数类型(以字节为单位)assetFilter: function(assetFilename) {// 提供资源文件名的断言函数return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');}},devtool: "source-map", // enumdevtool: "inline-source-map", // 嵌入到源文件中devtool: "eval-source-map", // 将 SourceMap 嵌入到每个模块中devtool: "hidden-source-map", // SourceMap 不在源文件中引用devtool: "cheap-source-map", // 没有模块映射(module mappings)的 SourceMap 低级变体(cheap-variant)devtool: "cheap-module-source-map", // 有模块映射(module mappings)的 SourceMap 低级变体devtool: "eval", // 没有模块映射,而是命名模块。以牺牲细节达到最快。// 通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试// 牺牲了构建速度的 `source-map' 是最详细的。context: __dirname, // string(绝对路径!)// webpack 的主目录// entry 和 module.rules.loader 选项// 相对于此目录解析target: "web", // 枚举target: "webworker", // WebWorkertarget: "node", // node.js 通过 requiretarget: "async-node", // Node.js 通过 fs and vmtarget: "node-webkit", // nw.jstarget: "electron-main", // electron,主进程(main process)target: "electron-renderer", // electron,渲染进程(renderer process)target: (compiler) => { /* ... */ }, // 自定义// 包(bundle)应该运行的环境// 更改 块加载行为(chunk loading behavior) 和 可用模块(available module)externals: ["react", /^@angular\//],externals: "react", // string(精确匹配)externals: /^[a-z\-]+($|\/)/, // 正则externals: { // 对象angular: "this angular", // this["angular"]react: { // UMDcommonjs: "react",commonjs2: "react",amd: "react",root: "React"}},externals: (request) => { /* ... */ return "commonjs " + request }// 不要遵循/打包这些模块,而是在运行时从环境中请求他们stats: "errors-only",stats: { //objectassets: true,colors: true,errors: true,errorDetails: true,hash: true,// ...},// 精确控制要显示的 bundle 信息devServer: {proxy: { // proxy URLs to backend development server'/api': 'http://localhost:3000'},contentBase: path.join(__dirname, 'public'), // boolean | string | array, static file locationcompress: true, // enable gzip compressionhistoryApiFallback: true, // true for index.html upon 404, object for multiple pathshot: true, // hot module replacement. Depends on HotModuleReplacementPluginhttps: false, // true for self-signed, object for cert authoritynoInfo: true, // only errors & warns on hot reload// ...},plugins: [// ...],// 附加插件列表/* 高级配置(点击展示) */resolveLoader: { /* 等同于 resolve */ }// 独立解析选项的 loaderparallelism: 1, // number// 限制并行处理模块的数量profile: true, // boolean// 捕获时机信息bail: true, //boolean// 在第一个错误出错时抛出,而不是无视错误。cache: false, // boolean// 禁用/启用缓存watch: true, // boolean// 启用观察watchOptions: {aggregateTimeout: 1000, // in ms// 将多个更改聚合到单个重构建(rebuild)poll: true,poll: 500, // 间隔单位 ms// 启用轮询观察模式// 必须用在不通知更改的文件系统中// 即 nfs shares(译者注:Network FileSystem,最大的功能就是可以透過網路,讓不同的機器、不同的作業系統、可以彼此分享個別的檔案 ( share file ))},node: {// Polyfills and mocks to run Node.js-// environment code in non-Node environments.console: false, // boolean | "mock"global: true, // boolean | "mock"process: true, // boolean__filename: "mock", // boolean | "mock"__dirname: "mock", // boolean | "mock"Buffer: true, // boolean | "mock"setImmediate: true // boolean | "mock" | "empty"},recordsPath: path.resolve(__dirname, "build/records.json"),recordsInputPath: path.resolve(__dirname, "build/records.json"),recordsOutputPath: path.resolve(__dirname, "build/records.json"),// TODO}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
