webpack学习笔记(一)

202 阅读4分钟

一、webpack开始

  • webpack是什么?
    webpack是一个javascript应用程序的静态模块化打包工具,它会从入口模块出发,识别出源码中的模块化导入语句,递归地找出入口文件的所有依赖,构建一个依赖关系图。然后将这些模块打包成一个或多个bundle。
  • webpack安装
    • 全局安装 不推荐
    # 安装webpack V4+版本时,需要额外安装webp
    npm install webpack webpack-cli -g
    
    ps:全局安装webpack,这会将项目的webpack锁定到指定版本,如果有项目并不是这个webpack版本,会导致构建失败。
    • 项⽬安装 推荐
    npm install webpack webpack-cli -D
    npm i -D webpack@<version>
    
    实现了在不同项目中可以安装不同版本的webpack。
    • 检查安装
    #command not found 默认在全局环境中查找
    webpack -v 
    # npx帮助我们在项⽬中的node_modules⾥查找webpack
    #./node_modules/.bin/webpack -v//到当前的node_modules模块⾥指定
    npx webpack -v
    webpack
    
  • webpack默认配置
    webpack默认⽀持JS模块和JSON模块,⽀持CommonJS Es moudule AMD等模块类型,webpack4⽀持零配置使⽤,但是很弱,稍微复杂些的场景都需要额外扩 展。
    webpack有默认的配置⽂件,叫webpack.config.js,我们可以对这个⽂件进⾏修改,进⾏个性化配置。不使⽤⾃定义配置⽂件: ⽐如webpackconfig.js,可以通过--config webpackconfig.js来指定webpack使⽤哪个配置⽂件来执⾏构建。
    const path = require("path");
    module.exports = {
     // 必填 webpack执⾏构建⼊⼝
     entry: "./src/index.js",
     output: {
         // 将所有依赖的模块合并输出到main.js
        filename: "main.js",
         // 输出⽂件的存放路径,必须是绝对路径
        path: path.resolve(__dirname, "./dist"),
        //在生产环境有效,打包过的静态资源都会加上这个前缀
        publicPath:'https://cdn.com/'
     }
    };
  • 执行webpack
# npx⽅式
npx webpack
# npm script
npm run test
#修改package.json⽂件: 
    "scripts": {
        "build": "webpack --config webpack.dev.config.js"
    }

二、webpack核心

2.1 entry和output基础配置

  • entry Webpack 执⾏构建的第⼀步将从 Entry 开始。
    //单⼊⼝ SPA,本质是个字符串
    entry:{
     main: './src/index.js'
    }
    ==相当于简写===
    entry:"./src/index.js"
    //多⼊⼝ entry是个对象
    entry:{
     index:"./src/index.js",
     login:"./src/login.js"
    }
    
  • output
    打包转换后的⽂件输出到磁盘位置:输出结果,在 Webpack 经过⼀系列处理 并得出最终想要的代码后输出结果。filename表示输出文件的名称,而输出⽂件到磁盘的⽬录,必须是绝对路径。
    output: {
     filename: "bundle.js",
     path: path.resolve(__dirname, "dist")
    },
    //多⼊⼝的处理
    output: {
     filename: "[name][chunkhash:8].js",//利⽤占位符,⽂件名称不要重path: path.resolve(__dirname, "dist")
    },
    

2.2 mode

通过选择 development 或 production 之中的一个,来设置 mode 参数。设置mode可以⾃动触发webpack内置的函数,达到优化的效果。

2.3 module

在 Webpack ⾥⼀切皆模块,⼀个模块对应着⼀个⽂件。Webpack 会 从配置的 Entry 开始递归找出所有依赖的模块。当webpack处理到不认识的模块时,需要在webpack中的module处进⾏配置,当检测到是什么格式的模块,使⽤什么loader来处理。

2.4 loader

用于对模块的源代码进行转换。webpack是模块打包工具,但是只支持js和json模块。对其他格式的处理需要loader。

  • 样式相关loader
    Style-loader 会把css-loader⽣成的内容,以style挂载到⻚⾯的header部分。
    npm install style-loader css-loader -D
    
        module:{
            rules:[
                {
                    test:/\.css$/,
                    use:[{
                        loader:"style-loader",
                        options:{
                            // 将所有的style标签合并成⼀个
                            injectType:"singletonStyleTag"}
                        },"css-loader"
                    ]
                }
            }
        }
    
    less-loader 把less语法转换成css,loader有顺序,从右到左,从下到上。
    $ npm install less less-loader --save-dev
    
    {
     test: /\.scss$/,
     use: ["style-loader", "css-loader", "less-loader"]
    }
    
    样式添加前缀
     npm i postcss-loader autoprefixer -D
    
    //webpack.config.js
    {
      test: /\.css$/,
      use:[
            "style-loader",
            {   
                loader:"css-loader",
                options:{
                    //js或者css中通过import导入的css,保证解析css的loader,从右边第1个依次解析。
                    importLoaders:1
                }
            },
            "postcss-loader"
        ]
    },
    //新建postcss.config.js
    module.exports = {
        plugins: [
            require("autoprefixer")({
                overrideBrowserslist: ["last 2 versions", ">1%"]
            })
       ]
    }
    
  • 加载图片
    npm install file-loader -D
    
    {
        test:/\.(png|jpg|gif)$/,
        use:[{
            loader:"file-loader",
            options:{
                name:"[name]_[hash].[ext]",
                outputPath:"images/"
            }
        }]
    }
    
    npm install url-loader -D  
    
    url-loader内部使用了file-loader。区别是它解析jpg时,会转换为base64格式,对小体积的图片比较合适,对体积大的图片并不合适,选项可以设置limit,体积小于这个数值,则会转换为base64。
    {
        test:/\.(png|jpg|gif)$/,
        use:[{
            loader:"url-loader",
            options:{
                name:"[name]_[hash].[ext]",
                outputPath:"images/",
                <!--单位 byte-->
                limit:1024
            }
        }]
    }
    
  • 加载字体
    {
         test: /\.(woff|woff2|eot|ttf|otf)$/,
         use: [
          'file-loader'
        ]
    }
    

2.5 Plugins

plugin 可以在webpack运⾏到某个阶段的时候,帮你做⼀些事情,类似于⽣ 命周期的概念,作用于整个构建过程。
扩展插件,在 Webpack 构建流程中的特定时机注⼊扩展逻辑来改变构建结 果或做你想要的事情。

  • 管理输出
    htmlwebpackplugin会在打包结束后,⾃动⽣成⼀个html⽂件,并把打包⽣ 成的js模块引⼊到该html中。仓库地址:github.com/jantimon/ht…。clean-webpack-plugin用于每次构建前清理/dist文件夹。
npm install --save-dev html-webpack-plugin
npm install --save-dev clean-webpack-plugin
plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
        title:"webpack-train",
        filename:"index.html",
        //原来的html文件地址
        template:"./index.html",
        inject:true
    })
]

2.6 source map

将编译后的代码映射回原始源代码,为了更容易地追踪错误和警告。devtool这个选项控制是否生成,以及如何生成 source map。 source-map生成.map⽂件;inline:将.map作为dataURI嵌入到输出文件中。cheap:报错代码定位到行,它没有生成列映射;eval:速度最快,会忽略源自loader的source map;Module:源自 loader 的 source map 会得到更好的处理结果。
配置推荐:

devtool:"cheap-module-eval-source-map",// 开发环境配置
devtool:"none" //none或者source-map适用于生产环境

2.7 WebpackDevServer

每次要编译代码时,手动运行 npm run build 就会变得很麻烦。webpack 中有几个不同的选项,可以帮助你在代码发生变化后自动编译代码:webpack's Watch Mode。
启动服务后,会发现dist⽬录没有了,这是因为devServer把打包后的模块不 会放在dist⽬录下,⽽是放到内存中,从⽽提升速度 、webpack-dev-server、webpack-dev-middleware。

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch",
    "build": "webpack"
}

webpack-dev-server 为你提供了一个简单的 web 服务器,并且能够实时重新加载。 配置:

# package.json
"scripts": {
 "server": "webpack-dev-server"
 }

contentBase配置html所在路径,publicPath配置在浏览器访问的路径,默认为:'/'。

devServer:{
    port:"8080",
    open: true,
    hot:true,
    contentBase:'./index.html',
    //访问路径变成:http://localhost:8080/assets/
    publicPath:'/assets/'
}

2.8 热模块替换

模块热替换(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,而无需进行完全刷新。

  • HMR 修改样式表
    借助于 style-loader 的帮助,CSS 的模块热替换实际上是相当简单的。当更新 CSS 依赖模块时,此 loader 在后台使用 module.hot.accept 来修补(patch) style 标签。因此需要配置style-loader、css-loader。启动HMR后,样式修改,页面也会随之更改,且不会刷新页面。
    注意启动HMR后,css抽离会不⽣效,还有不⽀持contenthash,chunkhash。 hot 和 hotOnly 的区别是在某些模块不支持热更新的情况下,前者会自动刷新页面,后者不会刷新页面,而是在控制台输出热更新失败
//热模块替换是webpack内置插件
const webpack = require("webpack");
//webpack-server配置
devServer: {
     contentBase: "./dist",
     open: true,
     hot:true,
     //即便HMR不⽣效,浏览器也不⾃动刷新,就开启hotOnly
     hotOnly:true
 }
//插件配置处
plugins: [
    new webpack.HotModuleReplacementPlugin()
 ]
  • 处理js模块HMR 。 如果已经通过HMR启用了模块热替换,则它的接口将被暴露在module.hot属性下面。通常,用户先要检查这个接口是否可访问,然后再开始使用它。接受(accept)给定依赖模块的更新,并触发一个 回调函数 来对这些更新做出响应。
if (module.hot) {
    module.hot.accept('./number.js', function() {
        number();
   })
}

2.9 Babel处理ES6

babel-loader只是webpack与babel的通信桥梁,因此需要借助@babel/preset-env将es6转换为js;@babel/preset-env⾥包含了es,6,7,8转es5的转换规则。 babel地址:www.babeljs.cn/docs/babel-…

npm i babel-loader @babel/core @babel/preset-env -D     
{
    test:/\.js$/,
    exclude:/node_modules/,
    use: {
        loader: "babel-loader",
        options: {
          presets: ["@babel/preset-env"]
        }
    }
}

默认的Babel只⽀持let等⼀些基础的特性转换, Promise等⼀些还有转换过来,这时候需要借助@babel/polyfill,以查找目标环境中缺少的功能,并且仅包括所需的polyfill。www.babeljs.cn/docs/usage#…

npm install --save @babel/polyfill

rc结尾的文件通常代表运行时自动加载的文件,配置等等,.babelrc文件需要的配置项主要有预设(presets)和插件(plugins)。

#业务代码打包场景
//新建.babelrc文件
{"presets": [
    [
      "@babel/env",
      {
        //兼容的浏览器设置
        "targets": "> 0.2%, not dead",
        //按需注入,使用了usage,会自动引入import "@babel/polyfill",
        //无需在js中引入
        "useBuiltIns": "usage",
      }
    ]
]
}

当我们开发的是组件库,⼯具库这些场景的时候,polyfill就不适合了,因 为polyfill是注⼊到全局变量,window下的,会污染全局环境,所以推荐闭 包⽅式:@babel/plugin-transform-runtime,它不会造成全局污染。www.babeljs.cn/docs/babel-…

npm install --save-dev @babel/plugin-transform-runtime
# core.js2;npm install --save @babel/runtime-corejs2
npm install --save @babel/runtime
{
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "absoluteRuntime": false,
        #corejs: 2仅支持全局变量(例如Promise)和静态属性(例如Array.from"corejs": 2,
        "version": "^7.7.4"
      }
    ]
  ]
}