webpack基础学习

概念

webpack官网

webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图会映射项目所需的每个模块,并生成一个或多个 bundle
webpack主要使用场景是单页面富应用(SPA)。
简单来说,webpack就是一个.js配置文件,你的架构好或差都提现在这个配置里。

核心概念(最重要是前4个,一定要懂)

  • 入口(entry)
  • 输出(output)
  • loader
  • 插件(plugin)
  • 模式(mode)
  • 浏览器兼容性(browser compatibility)

安装

两种方式

  1. 运行npm i webpack -g全局安装webpack,这样就能在全局使用webpack的命令
  2. 在项目根目录中运行npm i webpack --save-dev安装到项目依赖中

配置

  • 基本配置
var path = require('path');

module.exports = {
  mode: 'development',
  entry: './foo.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js'
  }
};
  • 多个target

可以将单个配置导出为 object, functionPromise,还可以将其导出为多个配置。

webpack实时打包构建

  1. 由于每次重新修改代码之后,都需要手动运行webpack打包的命令,比较麻烦,所以使用**webpack-dev-server来实现代码实时打包编译,当修改代码之后,会自动进行打包构建。**
  2. 运行npm i webpack-dev-server --save-dev安装到开发依赖
  3. 安装完成之后,需要在package.json文件中配置运行webpack-dev-server命令,在scripts节点下新增"dev": "webpack-dev-server"指令
    1. 可以使用**--contentBase src**选项来修改dev指令,指定启动的根目录:(后面有更好的方法使用插件来指定启动页面)
    2. **--open **选项表示自动打开浏览器
    3. **--port 4321 **表示打开的端口号为4321
    4. **--hot **表示启用浏览器热更新
"dev": "webpack-dev-server --contentBase src --hot --port 4321 --open"

注意:发现可以进行实时打包,但是dist目录下并没有生成bundle.js文件,这是因为webpack-dev-server将打包好的文件放在了内存中。

入口(entry)

入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。

使用entry属性设置入口。

单个入口

用法:entry: string|Array<string>

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

等价于

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

对象语法

用法:entry: {[entryChunkName: string]: string|Array<string>}

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

优点:这些配置可以重复使用,并且可以与其他配置组合使用。用于将关注点从环境(environment)、构建目标(build target)、运行时(runtime)中分离。然后使用专门的工具(如webpack-merge)将它们合并起来。

多页面应用程序

在 webpack < 4 的版本中,通常将 vendor(第三方库) 作为单独的入口起点添加到 entry 选项中,以将其编译为单独的文件(与 CommonsChunkPlugin 结合使用)。而在 webpack 4 中不鼓励这样做。而是使用 optimization.splitChunks 选项,将 vendor 和 app(应用程序) 模块分开,并为其创建一个单独的文件。不要 为 vendor 或其他不是执行起点创建 entry。

module.exports = {
  entry: {
    pageOne: './src/pageOne/index.js',
    pageTwo: './src/pageTwo/index.js',
    pageThree: './src/pageThree/index.js'
  }
};

输出(output)

output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中。只指定一个 output 配置。

  • filename 用于输出文件名
const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }
};

多个入口起点

如果配置创建了多个单独的 “chunk”(例如,使用多个入口起点或使用像 CommonsChunkPlugin 这样的插件),则应该使用 占位符(substitutions) 来确保每个文件具有唯一的名称。

module.exports = {
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
};

选项

output: {
    publicPath: string, // 输出解析文件的目录,url 相对于 HTML 页面
    library: string, // 导出库(exported library)的名称
}

loader

webpack 只能理解 JavaScript 和 JSON 文件。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中。

配置

module.rules 允许你在 webpack 配置中指定多个 loader。

loader 从右到左地取值(evaluate)/执行(execute)。

  1. test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。(正则表达式匹配)
  2. use 属性,表示进行转换时,应该使用哪个 loader。
const path = require('path');

// 在下面的示例中,从 sass-loader 开始执行,然后继续执行 css-loader,最后以 style-loader 为结束。
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          },
          { loader: 'sass-loader' }
        ]
      }
    ]
  }
};

loader特性

  • loader 支持链式传递。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果(也就是应用过转换后的资源)传递给下一个 loader,依此类推。最后,链中的最后一个 loader,返回 webpack 期望 JavaScript。
  • loader 可以是同步的,也可以是异步的。
  • loader 运行在 Node.js 中,并且能够执行任何 Node.js 能做到的操作。
  • loader 可以通过 options 对象配置(仍然支持使用 query 参数来设置选项,但是这种方式已被废弃)。
  • 除了常见的通过 package.jsonmain 来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用 loader 字段直接引用一个模块。
  • 插件(plugin)可以为 loader 带来更多特性。
  • loader 能够产生额外的任意文件。

常用loader

  • url-loader 像 file loader 一样工作,但如果文件小于限制,可以返回 data URL。
  • file-loader 将文件发送到输出文件夹,并返回(相对)URL。
  • babel-loader 加载 ES2015+ 代码,然后使用 Babel 转译为 ES5。
  • html-loader 导出 HTML 为字符串,需要引用静态资源。
  • style-loader 将模块的导出作为样式添加到 DOM 中。
  • css-loader 解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码。
  • less-loader 加载和转译 LESS 文件。
  • sass-loader 加载和转译 SASS/SCSS 文件。
  • vue-loader 加载和转译 Vue 组件。
  • jshint-loader PreLoader,使用 JSHint 清理代码。

loader官方文档

示例:

通过 npm 安装指定loader。

module: { // 用来配置第三方loader模块的
    rules: [ // 文件的匹配规则
        { 
            test: /\.css$/, 
            use: ['style-loader', 'css-loader'] 
        },// 处理css文件的规则
        { 
            test: /\.(png|jpg|gif)$/, 
            use: 'url-loader?limit=43960' 
        }, // 通过limit指定进行base64编码的图片大小;只有小于指定字节(byte)的图片才会进行base64编码
    ]
}

使用babel处理高级JS语法

  1. 运行npm i babel-core babel-loader babel-plugin-transform-runtime --save-dev安装babel的相关loader包

  2. 运行npm i babel-preset-es2015 babel-preset-stage-0 --save-dev安装babel转换的语法

  3. webpack.config.js中添加相关loader模块,其中需要注意的是,一定要把node_modules文件夹添加到排除项:

    { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
    
  4. 在项目根目录中添加.babelrc文件,并修改这个配置文件如下:

    {
        "presets":["es2015", "stage-0"],
        "plugins":["transform-runtime"]
    }
    

注意:语法插件babel-preset-es2015可以更新为babel-preset-env,它包含了所有的ES相关的语法;

插件(plugin)

loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。

配置

使用一个插件,首先require() 进去,然后到 plugins 属性添加在数组中。多数插件可以通过选项(option)自定义。也可以在一个配置文件中因为不同目的而多次使用同一个插件,通过使用 new 操作符来创建它的一个实例。

const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
const webpack = require('webpack'); //访问内置的插件
const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    filename: 'my-first-webpack.bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader'
      }
    ]
  },
  plugins: [
    new webpack.ProgressPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

扩展

使用html-webpack-plugin插件配置启动页面

  1. 运行npm i html-webpack-plugin --save-dev安装到开发依赖
  2. 修改webpack.config.js配置文件如下:
// 导入处理路径的模块
var path = require('path');
// 导入自动生成HTMl文件的插件
var htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: path.resolve(__dirname, 'src/js/main.js'), // 项目入口文件
    output: { // 配置输出选项
        path: path.resolve(__dirname, 'dist'), 
        filename: 'bundle.js' // 配置输出的文件名
    },
    plugins:[ // 配置插件
        new htmlWebpackPlugin({
            template:path.resolve(__dirname, 'src/index.html'),//模板路径
            filename:'index.html'//自动生成的HTML文件的名称
        })
    ]
}

模式(mode)

告知 webpack 使用相应环境的内置优化。如果不声明默认production模式,即生产模式(压缩)。

用法:mode: 'none' | 'development' | 'production'

module.exports = {
  mode: 'production'
};
选项描述
development开发模式。会将 DefinePluginprocess.env.NODE_ENV 的值设置为 development。启用 NamedChunksPluginNamedModulesPlugin
production生产模式。会将 DefinePluginprocess.env.NODE_ENV 的值设置为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPluginTerserPlugin
none退出任何默认优化选项

解析(resolve)

resolver 帮助 webpack 从每个如 require/import 语句中,找到需要引入到 bundle 中的模块代码。

resolve: {
    // 解析模块请求的选项
    // (不适用于对 loader 解析)
    modules: [
      "node_modules",
      path.resolve(__dirname, "app")
    ],
    // 用于查找模块的目录
    extensions: [".js", ".json", ".jsx", ".css"],
    // 使用的扩展名
    alias: {
      // 模块别名列表
      // "别名": 模块或者js的绝对路径
      "module": path.resolve(__dirname, "app/third/module.js"),
      // 模块别名相对于当前上下文导入
    },
}

—————————————————————— 一条华丽的分割线 ————————————————————————

实战

const path = require('path');
module.exports = {
    // entry 表示入口,Webpack执行构建的第一步将从Entry开始,可抽象成输入
    // 类型可以是string、object、array
    entry: './app/entry', // 只有1个入口,入口只有1个文件
    entry: ['./app/entry1', './app/entry2'], // 只有1个入口,入口有两个文件
    entry: { // 有两个入口
        a: './app/entry-a',
        b: ['./app/entry-b1', './app/entry-b2']
    },
    // 如何输出结果:在Webpack经过一系列处理后,如何输出最终想要的代码
    output: {
        // 输出文件存放的目录,必须是string类型的绝对路径
        path: path.resolve(__dirname, 'dist'),

        // 输入文件的名称
        filename: 'bundle.js', // 完整的名称
        filename: '[name].js', // 在配置多个entry时,通过名称模板为不同的entry生成不同的文件名称
        filename: '[chunkhash].js', // 根据文件内容的Hash值生成文件的名称,用于浏览器长时间缓存文件
        // 发布到线上的所有资源的URL前缀,为string类型
        publicPath: '/assets/', // 放到指定目录下
        publicPath: '', // 放到根目录下
        publicPath: 'https://cdn.example.com/', // 放到CDN上
        // 导出库的名称,为string类型
        // 不填它时,默认的输出格式是匿名的立即执行函数
        library: 'MyLibrary',
        // 导出库的类型,为枚举类型,默认是var
        // 可以是umd、umd2、commonjs2、commonjs、amd、this、var、assign、window、global、jsonp
        libraryTarget: 'umd',
        // 是否包含有用的文件路径信息到生成的代码里,为boolean类型
        pathinfo: true,
        // 附加Chunk的文件名称
        chunkFilename: '[id].js',
        chunkFilename: '[chunkhash].js',
        // JSONP异步加载资源是的回调函数名称,需要和服务端搭配使用
        jsonpFunction: 'myWebpackJsonp',
        // 生成的Source Map文件的名称
        sourceMapFilename: '[file].map',
        // 浏览器开发者工具里显示的源码模块名称
        devtoolModuleFilenameTemplate: 'webpack:///[resource-path]',
        // 异步加载跨域的资源时使用的方式
        crossOriginLoading: 'use-credentials',
        crossOriginLoading: 'anonymous',
        crossOriginLoading: false,
    },
    // 配置模块相关
    module: {
        rules: [ // 配置Loader
            {
                test: /\.jsx?$/, // 正则匹配命中要使用Loader的文件
                include: [ // 只会命中这里面的文件
                    path.resolve(__dirname, 'app')
                ],
                exclude: [ // 忽略这里面的文件
                    path.resolve(__dirname, 'app/demo-files')
                ],
                use: [ // 使用哪些Loader,有先后持续,从后向前执行
                    'style-loader', // 直接使用Loader的名称
                    {
                        loader: 'css-loader',
                        options: {
                            // 向html-loader传一些参数
                        }
                    }
                ]
            },
        ],
        noParse: [ // 不用解析和处理的模块
            /special-library\.js$/ // 用正则匹配
        ],
    },
    // 配置插件
    plugins: [],
    // 配置寻找模块的规则
    resolve: { // 寻找模块的根目录,为array类型,默认以node_modules为根目录
        modules: [
            'node_modules',
            path.resolve(__dirname, 'app')
        ],
        extensions: ['.js', '.json', '.jsx', '.css'], // 模块的后缀命名
        alias: { // 模块别名配置,用于映射模块
            // 将'module'映射成'new-module',同样,'module/path/file'也会被映射成'new-module/path/file'
            'module': 'new-module',
            // 使用结尾符号$后,将'only-module'映射成'new-module',
            // 但是不像上面的,'module/path/file'不会被映射成'new-module/path/file'
            'only-modules$': 'new-module'
        },
        alias: [ // alias还支持使用数组来更详细地进行配置
            {
                name: 'module', // 老模块
                alias: 'new-module', // 新模块
                // 是否只映射模块,如果是true,则只有'module'会被映射;如果是false,则'module/inner/path'也会被映射
                onlyModule: true,
            }
        ],
        symlinks: true, // 是否跟随文件的软链接去搜寻模块的内容
        descriptionFile: ['package.json'], // 模块的描述文件
        mainFields: ['main'], // 模块的描述文件里描述入口的文件的字段名
        enforceExtension: false, // 是否强制导入语句写明文件后缀
    },
    // 输出文件的性能检测配置
    performance: {
        hints: 'warning', // 有性能问题时输出警告
        hints: 'error', // 有性能问题时出错错误
        hints: 'false', // 关闭性能检查
        maxAssetSize: 200000, // 最大文件的大小(单位为bytes)
        maxEntrypointSize: 400000, // 最大入口文件的大小(单位为bytes)
        assetFilter: function (assetFilename) { // 过滤要检查的文件
            return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
        }
    },
    devtool: 'source-map', // 配置source-map类型
    context: __dirname, // Webpack使用的根目录,string类型必须是绝对路径
    // 配置输出代码的运行环境
    target: 'web', // 浏览器,默认
    target: 'webworker', // WebWorker
    target: 'node', // Node.js,使用`require`语句加载Chunk代码
    target: 'async-node', // Node.js,异步加载Chunk代码
    target: 'node-webkit', // nw.js
    target: 'electron-main', // electron,主线程
    target: 'electron-renderer', // electron,渲染线程
    externals: { // 使用来自JavaScript运行环境提供的全局变量
        jquery: 'jQuery'
    },
    stats: { // 控制台输出日志控制
        assets: true,
        colors: true,
        errors: true,
        errorDetails: true,
        hash: true,
    },
    devServer: { // DevServer相关的配置
        proxy: { // 代理到后端服务接口
            '/api': 'http://localhost:3000'
        },
        contentBase: path.join(__dirname, 'public'), // 配置DevServer HTTP服务器的文件根目录
        compress: true, // 是否开启Gzip压缩
        historyApiFallback: true, // 是否开发HTML5 History API网页
        hot: true, // 是否开启模块热替换功能
        https: false, // 是否开启HTTPS模式
    },
    profile: true, // 是否捕捉Webpack构建的性能信息,用于分析是什么原因导致构建性能不佳
    cache: false, // 是否启用缓存来提升构建速度
    watch: true, // 是否监听
    watchOptions: { // 监听模式选项
        // 不监听的文件或文件夹,支持正则匹配。默认为空
        ignored: /node_modules/,
        // 监听到变发生后,等300ms再执行动作,截流,防止文件更新太快导致重新编译频率太快,默认为300ms
        aggregateTimeout: 300,
        // 不停地询问系统指定的文件有没有发生变化,默认每秒询问1000次
        poll: 1000,
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值