webpack4学习笔记

这里有一份简洁的前端知识体系等待你查收,看看吧,会有惊喜哦~若是以为不错,麻烦star哈~css


前言

webpack 是当下最好用的前端模块打包工具,前端开发人员平常都要跟脚手架打交道,而手脚架就是基于webpack构建的,深刻理解webpack,对咱们平常工做意义重大。html

本文将系统讲解webpack,老规矩,从应用维度跟设计维度展开,因为做者能力有限,有些部分暂时整理不出来,若是你有所补充,欢迎push~前端


应用维度


问题

从技术的应用维度看,首先考虑的是要解决什么问题,这是技术产生的缘由。问题这层,用来回答“干什么用”。node


随着前端的演变,网页已经至关于一个功能丰富的应用,前端面临诸多挑战:react

  1. 首先,前端代码愈来愈复杂,就须要模块化开发,模块化开发带来的问题就是代码如何组织,如何处理依赖关系?
  2. 前端社区日益繁荣,平常开发已经离不开第三方依赖,如何管理好第三方依赖,也成为一个问题。
  3. 浏览器对ES6的兼容还不够友好,这也是前端须要解决的问题
  4. 上线时咱们须要对代码进行打包,这样能够有效减小http请求,从而提升性能
  5. 咱们要打包的文件,不只包含JS,还可能包含CSS、image等。

因为前端界存在种种问题,webpack应运而生。jquery

webpack官方定义就是一个模块打包工具。webpack不只支持 ES module 的语法,也支持 CommonJS 的语法。webpack

webpack 不只能够打包JS,也能够打包其余格式的文件, 好比css、image等。git


技术规范

技术被研发出来,人们怎么用它才能解决问题呢?这就要看技术规范,能够理解为技术使用说明书。技术规范,回答“怎么用”的问题,反映你对该技术使用方法的理解深度。github


这里要重点讲解webpack的配置。web

模式

webpack 配置文件须要指定 mode,默认是production,打包后的文件会被压缩。能够指定成 development。不设置mode,会有警告

module.exports = {
  // ……
  mode: 'production',
}
复制代码

Entry 与 Output

entry 支持配置多项,每一项的key是文件名,当entry配置多个入口文件时,output的filename不能写死,否则会报错,能够写成 filename: [name].js

output 还能够配置publicPath,从而设置导出JS文件的前缀,经过这个配置,能够设置CDN地址。

module.exports = {
  entry: {
    main: './src/index.js',
    sub: './src/index.js'
  },
  output: {
    filename: '[name].js', // 设置成 index.js 会报错
    chunkFilename: '[name].chunk.js',
    publicPath: 'http://cdn.com',
    path: path.resolve(__dirname, '../dist')
  }
}
复制代码

Loader

loader就是打包方案。

好比,打包jpg图片时,可使用 file-loader 进行打包,也可使用url-loader,url-loader包含了 file-loader 全部的功能,并且,他默认会将图片转成base64格式。若是不但愿转成base64位,能够设置 limit,这样的话,当图片大于设置值的时候,就不会转成base64。

// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.(jpg|png|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name]_[hash].[ext]',
          outputPath: 'images/',
          limit: 10240
        }
      }
    }]
  }
}
复制代码

又好比,打包css文件时,须要同时引入两个loader:css-loader跟style-loader。css-loader会分析css文件的引用关系,最后把css文件合并成一段css。而style-loader的做用是把这段css放到head下的style标签下。

若是是scss文件,还须要引入 scss-loader。若是须要css自动添加浏览器产商前缀,则须要引入postcss-loader。

因为css中还能够引用其余的css,为了不出错,须要在css-loader 中设置importLoaders。

为了防止css全局污染,咱们须要引入css modules的概念,也就是css模块化。一样须要在css-loader 中设置 modules 为true。引入时可使用相似的方式: import style from './index.css'

若是css中引用了字体文件,还须要对 字体文件的格式设置loader,使用 file-loader 便可。

module.exports = {
  module: {
    rules: [{
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            modules: true
          }
        },
        'postcss-loader'
      ]
    }, {
      test: /\.(eot|ttf|svg)$/,
      use: {
        loader: 'file-loader'
      }
    }]
  },
}
复制代码
// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}
复制代码

若是有多个loader时,会从后往前执行。


plugins

使用plugins让打包更便捷。

plugin 很像生命周期函数,能够在webpack 运行到某一个时刻,帮你处理一些事情。

htmlWebpackPlugin 会在打包结束后,自动生成一个HTML文件,并把打包生成的JS自动引入到HTML中。

cleanWebpackPlugin 会在打包以前,删除某一个文件夹(好比dist文件夹)

module.exports = {
  // ……
  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/index.html'
    }),
    new CleanWebpackPlugin(['dist'], {
      root: path.resolve(__dirname, '../')
    })
  ]
}
复制代码

sourceMap

sourceMap 是一个映射关系,当咱们打包的文件报错时,它能提示咱们是源文件的出错位置,而不是打包后文件的出错位置,这样就利于调试。

使用方式,就是在 webpack 中配置 devtool: 'source-map'

development 环境,推荐使用 devtool: 'cheap-module-eval-source-map' production 环境,推荐使用 devtool: 'cheap-module-source-map'

module.exports = {
  // ……
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
}
复制代码

webpackDevServer

每次修改代码都要从新打包,这是很是繁琐的,咱们能够修改npm scripts成webpack --watch

但若是咱们想实现更酷炫的效果,好比自动打开浏览器、自动刷新浏览器等,这个操做就作不到。此时,能够借助webpackDevServer 来实现。

webpack支持 devServer , 能够帮咱们启动了一个服务器。咱们在平常开发中,常常须要发ajax请求,这大大提升了咱们的开发效率。此外,devServer打包后的文件,其实保存在内存中,这样打包的速度更快。

以前 devServer 还不够完善,因此不少脚手架工具会本身实现一个devServer,如今webpack的devServer已经很是完善了。

更多请参考官网

module.exports = {
  devServer: {
    contentBase: './dist', // 服务器的根目录
    open: true, // 自动打开浏览器
    port: 8080,
    hot: true,
    proxy: { // 设置代理,访问/api,直接转发到3000端口
      "/api": "http://localhost:3000"
    }
  },
}
复制代码

咱们也能够手写一个 devServer,新建server.js,增长 npm scripts : node server.js

const express = require('express);
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('./webpack.config.js');
const complier = webpack(config)

const app = express(); // 启动一个http服务器
app.use(webpackDevMiddleware(complier, {}))

app.listen(3000, ()=>{
  console.log("server is running");  
})
复制代码

经过这个例子,也能够看到webpack有两种使用方式,一种是在命令行中使用,一种是在node中直接使用webpack。

在命令行使用webpack,能够参考官网资料

在node中使用webpack,能够参考官网资料


hot mudule replacement 热更新

咱们每一次修改代码,devServer都会帮咱们刷新页面,但咱们只但愿显示修改的内容,而不刷新页面,此时就要用到热更新。

更多请参考官网资料1资料2

const webpack = require('webpack');

module.exports = {
  devServer: {
    contentBase: './dist',
    open: true,
    port: 8080,
    hot: true,
    hotOnly: true, // 可选,即使hot功能不生效,浏览器也不刷新
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
}
复制代码

Babel

有些浏览器还不支持ES6的语法,此时就须要用babel转义,将ES6语法转成ES5。

babel提供了详细的使用指南,在官网setup页面选择webpack选项就能够看到。


babel的使用分为三步:

  1. Installation
npm install --save-dev babel-loader @babel/core
复制代码

babel-loader @babel/core 是 babel 跟 webpack 之间的桥梁

  1. Usage
module: {
  rules: [
    { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
  ]
}
复制代码
  1. Create .babelrc configuration file 新建 .babelrc 并按照 env preset
npm install @babel/preset-env --save-dev
复制代码
// .babelrc
{
  "presets": ["@babel/preset-env"]
}
复制代码

@babel/preset-env 将ES6的语法转义成ES5语法,好比let转成var

@babel/polyfill 为低级浏览器注入了ES6的对象或方法,好比promise

引入 @babel/polyfill 会让咱们的文件变得很是大,能够配置 useBuiltIns 作到按需加载

babel 内容很是多,建议直接看官网。


module.exports = {
  // ……
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader',
      options: {
        presets: [["@babel/preset-env", {
          targets: {
            chrome: '67',  // 告诉 babel 目标浏览器,babel能够根据目标浏览器决定是否作转化,这样就能够减小最终输出文件的大小
          },
          useBuiltIns: 'usage  // 提升性能:用到的才引用
        }]]
      }
      // use: [{
      //   loader: 'babel-loader'
      // }, {
      //   loader: 'imports-loader?this=>window'
      // }]
    }]
  },
}
复制代码

babel-loader 中 options 的内容会很是多,能够把 options 的内容放到 .babelrc 中


tree shaking

咱们引入一个模块,只会引入该模块中的部分方法,tree shaking会帮咱们把不须要的方法过滤掉,这样打包后的文件将显著变小。

tree shaking 只支持 ES Module 的引用方式。

development 模式下,默认是不支持 tree shaking,咱们须要配置 optimization 的 usedExports 为true。

咱们还须要给 package.json 增长一项配置 "sideEffects": ["@babel/polyfill", "*.css"],这样打包时 tree shaking 对 @babel/polyfill就不会有做用。这是由于咱们引用@babel/polyfill时,是import @babel/polyfill,tree shaking 会认为 @babel/polyfill 不须要引用任何东西,从而把它忽略掉。同理,咱们可使用 import "index.css",咱们一样不但愿tree shaking生效,咱们能够在sideEffects中增长 *.css 的配置。

若是设置"sideEffects": false,表示对全部模块都作 tree shaking。

development 模式下,为了调试方便,虽然设置了 tree shaking,但打包出来的文件同样包含没有引用的模块。当咱们上线时,会设置 mode 为 production,此时 tree shaking 就会把不须要模块的代码过滤掉。

module.exports = {
  // ……
  mode: 'development',
  optimization: {
    usedExports: true,
  },
}
复制代码

development 和 production 模式的区分打包

因为 development 和 production 模式下的配置是不同的,咱们能够抽离出公共的 webpack.common.js,以及Dev下的 webpack.dev.js 和 production下的webpack.prod.js。最后使用 webpack.merge 合并。

const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');

const devConfig = {
  // ……
}

module.exports = merge(commonConfig, devConfig);
复制代码

splitChunksPlugin

webpack代码分割底层使用了 splitChunksPlugin 插件。官网资料地址

module.exports = {
  splitChunks: {
    chunks: "async", // 可选:all。async 只代码分割异步代码,all同时支持同步跟异步的方式
    minSize: 30000, // 小于 30KB 不作代码分割,大于 30KB,还要根据cacheGroups的规则决定是否作代码分割
    maxSize: 20000, // 大于 20KB 尝试作代码分割,但因为基础库是不容许分割的,因此通常不生效
    minChunks: 1,  // 引用超过1次,会作代码分割。
    maxAsyncRequests: 5, // 遇到的前5个库,会作代码分割,超过5个的不作代码分割
    maxInitialRequests: 3, // 入口文件最多只能作三次代码分割
    automaticNameDelimiter: '~', // 文件链接符
    name: true, // 为true时,cacheGroups的filename才会生效
    cacheGroups: { // 缓存组,知足以上要求的文件,会根据缓存组中的要求,加入缓存组,最终打包成文件。这样的好处是能够把多个库,输出成一个文件。此外,若是配置了上面的参数却没有代码分割,极可能就是缓存组的配置不知足
      vendors: {
        test: /[\\/]node_modules[\\/]/, // node_modules目录下的文件会被匹配
        priority: -10, // 优先级,值越大优先级越大
        // filename: 'vendors.js'
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true  // 若是一个模块已经被打包了,则再打包时会忽略该模块
      }
    }
  },
}
复制代码

小技巧:splitChunks 若是不配置,默认值就是上面的这些选项。简便写法是:

module.exports = {
  // …… 
  splitChunks: {
    chunks: "all", // 咱们要对同步跟异步代码都作代码分割,因此改为all
  },
}
复制代码

咱们也能够为css进行代码分割,使用到的插件是MiniCssExtractPlugin,只须要用MiniCssExtractPlugin提供的loader 代替 style-loader 便可,具体内容看官网。


最佳实践

最佳实践回答“怎么能用好”的问题,反映你实践经验的丰富程度。


webpack的安装

webpack 不建议全局安装,由于每一个项目依赖的webpack版本可能不一样,全局安装可能致使项目依赖的webpack版本不对而没法运行,建议局部安装,也就是 npm i webpack webpack-cli -D

局部安装完webpack后,若是要查看webpack的版本,执行 webpack -v是得不到预期的结果,由于webpack并没全局安装,此时要执行 npx webpack -v,npx是npm提供的命令,它会在咱们当前目录下的node_modules文件下寻找安装过的依赖。

若是咱们是在package.json文件中配置 npm scripts,则不须要npx这个指令,由于 npm scripts 默认会在当前目录下的 node_modules 寻找依赖。

安装webpack时,能够指定webpack的版本号,若是不清楚webpack有什么版本,可使用npm info webpack查看

webpack-cli 容许咱们在命令里使用webpack这个命令。

webpack与 code splitting

若是把全部的代码都打包到一个文件里,会带来两个问题:

  1. 文件过于庞大
  2. 基础库基本上不会改变,而业务代码却常常改变,一旦业务代码更改了,整个文件要从新加载,会极大的损耗性能。

code splitting 是代码分割,没有webpack咱们也能够手动作代码分割,从而提高性能。webpack能帮咱们自动完成代码分割。

webpack 中实现代码分割有两种方式:

  1. 同步代码,咱们能够在 optimization 中设置splitChunks。
  2. 异步代码(import),无需任何配置,会自动进行代码分割。
module.exports = {
  // ……
  optimization: {
    splitChunks: {
      chunks: 'all',
    }
  },
}
复制代码

打包分析

咱们可使用webpack提供的analyse工具进行打包分析.

咱们在打包时,须要增长命令webpack --profile --json > stats.json,也就是 webpack --profile --json > stats.json --config ./build/webpack.dev.js

打包完的文件中,就会出现stats.json的文件。

咱们打开连接,上次stats.json,就会出现打包的分析报告。

webpack官方提供的分析工具,除了analyse,还有这些

  1. webpack-chart: webpack 数据交互饼图。
  2. webpack-visualizer: 可视化并分析你的 bundle,检查哪些模块占用空间,哪些多是重复使用的。
  3. webpack-bundle-analyzer: 一款分析 bundle 内容的插件及 CLI 工具,以便捷的、交互式、可缩放的树状图形式展示给用户。

Prefetching/Preloading

webpack 建议咱们写异步加载代码,也就是异步import。当代码执行时,才会去加载相应的代码,这样首屏的代码利用率就能够提升。相似:

document.addEventListener('click', () => {
  import('./click.js').then(({ default: func }) => {
    func()
  })
})
复制代码

咱们能够用Chrome的coverage工具看代码的利用率。



但咱们不必定要等到用户操做时,才去加载相应的代码,而是在网络空闲时就去加载。咱们能够在webpack中进行配置。具体作法以下:

// 关注下魔法注释,js的新特性
document.addEventListener('click', () => {
  import(/* webpackPrefetch: true */ './click.js').then(({ default: func }) => {
    func()
  })
})
复制代码

Prefetching/Preloading 是有区别的:

  1. Prefetching会等待核心代码加载完,网络空闲时才去加载
  2. Preloading是跟主要的代码一块加载的

因此Prefetching会更合适。


webpack 与 浏览器缓存

咱们打包的文件,浏览器是会缓存的,当咱们修改了内容,用户刷新页面,此时加载的仍是缓存中的文件。为了解决这个问题,咱们须要修改production模式下的配置文件。

const commonConfig = require('./webpack.common.js');

const prodConfig = {
  mode: 'production',
  devtool: 'cheap-module-source-map',
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].js'
  },
  optimization: {
    runtimeChunk: {
      name: 'runtime'  // 旧版本必须配置此项,不然即使文件内容没有发生改变,hash值也会改变
    },
  }
}

module.exports = merge(commonConfig, prodConfig);
复制代码

contenthash 会根据文件内容生成hash值,当咱们文件内容改变时,contenthash就会改变,从而通知浏览器从新向服务器请求文件。

之因此在旧版webpack下,文件代码没变,生成文件的hash值也会改变的缘由是:

咱们业务逻辑的代码打包到main.js里,依赖库的代码打包到vendors.js里,但main.js跟vendors.js是有依赖关系的,这些依赖关系的代码会保存在manifest文件里。manifest文件既存在于main.js,也存在vendors.js里。而在旧版webpack每次打包manifest可能会有差别,这个差别致使vendors.js的hash值也会改变。设置runtimeChunk后,manifest相关的代码会被抽离出来,放到runtime文件里去,这样就能解决这个问题。


Shimming 垫片

jQuery时代,咱们须要先引入jQuery,再引入其余依赖jQuery的类库,好比jQuery.ui.js。这在webpack中就有问题。好比这样:

// a.js
import $ from 'jquery'
import 'jquery.ui'
复制代码

这样引用,jquery.ui.js会报错:找不到。之因此这样,是由于webpack是模块化,只能在a.js里引用,jquery.ui.js是引用不到$的,而jquery.ui.js是第三方库,咱们又不能去修改jquery.ui.js的代码,怎么办呢?

咱们能够添加ProvidePlugin插件。在ProvidePlugin里咱们设置了,当JS文件中用到,在当前又没引用时,这个配置就会生效,告诉JS文件指向jquery。

关于ProvidePlugin,能够到官网看资料

const webpack = require('webpack');
module.exports = {
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      _join: ['lodash', 'join']
    }),
  ],
  performance: false, // 额外补充:设置为false,打包时不会警告性能方面的问题
}
复制代码

关于垫片机制,还有其余用法。好比咱们在一个模块中全局打印this,发现this指向的是模块自己,而不是window对象,若是想要让this指向window,能够这样:

module.exports = {
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      use: [{
        loader: 'babel-loader'
      }, {
        loader: 'imports-loader?this=>window'
      }]
    }]
  },
}
复制代码

咱们须要安装imports-loader,设置this指向window。

关于shimming,能够看官网资料


library 的打包

咱们写的库,要支持多种方式的引用,诸如:

// library.js
export function math (){
  console.log(1);
}
复制代码
import library from './library' // ES module
const library = require('library'); // commonjs
require(['library'], function(){}) // AMD
复制代码

咱们能够配置libraryTarget:

module.exports = {
  mode: 'production',
  entry: {
    main: './src/index.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    libraryTarget: 'umd' // umd 是通用的意思。配置了umd,就能够支持不一样的引用方式
  }
}
复制代码

若是你还想经过script标签引用,好比<script src="./library.js"></script>,那还须要配置

module.exports = {
  mode: 'production',
  entry: {
    main: './src/index.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    library: 'library', // 打包好的代码,挂载到页面library这个全局变量上
    libraryTarget: 'umd' // umd 是通用的意思。配置了umd,就能够支持不一样的引用方式
  }
}
复制代码

打包后到浏览器控制台输入library,就会打印出全局变量



这里要重点讲下 library 跟 libraryTarget 的关系。library的含义是要生成一个全局变量, libraryTarget 的含义是这个全局变量挂载到哪里。若是libraryTarget设置为umd,则二者关系不大。若是咱们把libraryTarget 设置成this,则打包出来的文件不支持ES module、commonjs等的引用,他表示全局变量挂载到全局的this上。此时咱们在浏览器控制台,输入this.library,就能够找到该全局变量。libraryTarget 还设置成 window、global。

此外,咱们在打包时,还会出现一种状况:

// library.js
import _ from lodash;
// 其余代码
复制代码
// a.js
import _ from lodash;
import library from './library';
复制代码

这就形成lodash被打包了两次,咱们但愿library.js打包时,不要把lodash打包进去,能够这样配置:

module.exports = {
  externals: ['lodash] // 打包时,遇到lodash,自动忽略
}
复制代码

PWA

咱们把生成的文件放到线上,用户就能够访问,若是服务器挂了,页面就会显示异常。这种时候,咱们但愿即使服务器挂了,用户仍是能够看到以前访问的页面,而这就是PWA。

要作到PWA很简单,首先配置webpack。

const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
module.exports = {
  plugins: [
    new WorkboxWebpackPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: true
    }),
  ]
}
复制代码

而后在业务代码中,使用 serviceWorker。

if('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js')
      .then(registration => {
        console.log('service-worker register')
      }).catch(error => {
        console.log('service-worker register error')
      })
  })
}
复制代码

请求转发

咱们在开发时,常常会遇到跨域的问题,devServer 能够帮助咱们实现请求转发,具体看官网资料

咱们只须要在webpack进行以下配置:

module.exports = {
  devServer: {
    proxy: {
      '/react/api': {
        target: 'https://baidu.com/',
        secure: false, // false 时才能够对https请求的转发
        pathRewrite: {
          'header.json': 'demo.json'
        }
      }
    }
  },
}
复制代码

devServer 中的proxy容许咱们作请求转发。当咱们请求'/react/api'就会被转发到http://baidu.com/的域名下。此外,咱们在平常开发中,可能须要用到header.json这个API时,该API还没开发完,咱们须要先访问demo.json进行开发,此时就能够设置pathRewrite达到效果。

webpack的proxy内容很是多,底层使用的是http-proxy-middleware,能够上GitHub看相应的资料


单页面路由问题

咱们在写react应用时,须要用到react-router-dom实现路由,可是咱们会发现,当咱们访问/list时,预期是要访问到/list路由,但浏览器会发送请求到/list,从而页面显示出错。

要解决这个问题,就要用到devServer的historyApiFallback这个API了。

当咱们在devServer里配置historyApiFallback:true后,咱们无论访问什么url,都会执行根目录(也就是/)下的代码,从而解决了单页路由的问题。

更多内容,看官网


eslint

eslint 跟 webpack关系不大,不少编辑器是能够支持eslint插件,但可能咱们为了调试方便,但愿eslint的错误显示在浏览器上,这样即使咱们编辑器没有eslint插件,也能够看到问题。

操做起来也很简单,咱们先在本身的工程里安装eslint跟eslint-loader.

module.exports = {
  devServer: {
    overlay: true  // 必须配置
  },
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: ["babel-loader", "eslint-loader"],  // 使用 eslint-loader 
    },
  ]
}
复制代码

关于eslint-loader,能够看官网资料


webpack性能优化

  1. 跟上技术迭代(Node yarn npm )
  2. 在尽量少的模块上应用loader
  3. plugin 尽量精简并确保可靠
  4. 合理配置resolve。
  5. 使用 DllPlugin 提升打包速度(5.十、5.11)
  6. 控制包文件大小
  7. 合理使用sourceMap
  8. 结合 stats 分析打包结果
  9. 开发环境内存编译(devServer打包文件存于内存,能提升速度)

跟上技术迭代

webpack运行于node,node版本更新,天然会提升webpack的打包效率,npm跟yarn等包管理工具也是同理。


在尽量少的模块上应用loader

为loader配置exclude,例如: exclude: /node_moudles/ 为loader配置include,例如:include: path.resolve(__dirname, '../src')


plugin 尽量精简并确保可靠

好比开发环境下,不须要对代码进行压缩,这样就不须要在webpack.dev.js里引入相关的plugin


合理配置resolve

当咱们没有写js后缀时,webpack默认会帮咱们补上,若是咱们的jsx文件也不但愿写上后缀,但愿webpack会帮咱们默认补上,能够设置resolve。


module.exports = {
  resolve: {
    extensions: ['.js', '.jsx'],
    mainFiles: ['index', 'child'] // 当咱们引用的是某个路径,webpack默认会帮咱们读取index文件,若是咱们设置了['index', 'child'],webpack会逐一帮咱们查找index.js index.jsx child.js child.jsx
  }
}
复制代码

市场应用趋势

随着技术生态的发展,和应用问题的变迁,技术的应用场景和流行趋势会受到影响。这层回答“谁用,用在哪”的问题,反映你对技术应用领域的认识宽度。


设计维度


目标

为了解决用户的问题,技术自己要达成什么目标。这层定义“作到什么”。


webpack就是个模块打包工具,咱们须要使用webpack打包不限于JS、CSS、image等文件。

不一样的文件,打包策略是不一样的,因此咱们须要配置loader。

打包过程当中,咱们可能还须要作一些额外的操做,因此咱们须要配置 plugin。

因此学习webpack的重点,就是理解与掌握loader跟plugin。

webpack 默认会读取 webpack.config.js文件,咱们也能够更改默认的文件名npx webpack --config webpack.xxx.js

注:webpack开发团队为了提升开发体验,一直在丰富webpack的默认配置,因此咱们虽然没有指定JS的打包策略,但同样能够打包成功。


实现原理

为了达到设计目标,该技术采用了什么原理和机制。实现原理层回答“怎么作到”的问题。把实现原理弄懂,而且讲清楚,是技术人员的基本功。


优劣局限

每种技术实现,都有其局限性,在某些条件下能最大化的发挥效能,缺乏了某些条件则暴露出其缺陷。优劣局限层回答“作得怎么样”的问题。对技术优劣局限的把握,更有利于应用时总结最佳实践,是分析各类“坑”的基础。

演进趋势

技术是在迭代改进和不断淘汰的。了解技术的前生后世,分清技术不变的本质,和变化的脉络,以及与其余技术的共生关系,能体现你对技术发展趋势的关注和思考。这层体现“将来如何”。

相关文章
相关标签/搜索