手动配置webpack

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qzf_hainenggaima/article/details/88146739

一、webpack介绍

webpack其实就是javascript应用程序的静态模块的打包器。

核心概念:
入口(entry)、输出(output)、loader、插件(plugins)

作用:
webpack会将项目的资源文件当成一个个模块,模块之间有依赖关系(比如js和png,js会动态的改变引入一个图片,css设置背景图片和png有依赖,webpack会对这些依赖进行处理,让浏览器识别出来),webpack会对这些有依赖关系的文件进行处理,让浏览器识别,最后将应用程序需要的每个模块打包成一个或多个bundle。

目标:
1、切分依赖树,把依赖树切分到不同的代码块里,然后按需加载这些依赖(和懒加载概念像)
2、保持初始化的时间更少
3、任何的资源都应该视为一个模块在项目中被引用
4、整合第三方的类库,把第三方的类库也视为他的模块
5、每个打包部分都可以自定义,做自己的事情
6、适合大型项目

优势:
1、code splitting
2、loaders
3、plugin system 模块热更新提高开发和调试的效率

二、手动配置webpack(0-1)

自己配置完成的源码:https://github.com/qiuzhaofeng/webpackdemo

1、首先安装node,然后咱们建个新文件,在这里面开始我们的webpack之旅。
2、创建package.json文件,里面是项目相关信息,npm init
3、安装webpack

  • 本地安装:(推荐)
    npm install --save-dev webpack
    npm install --save-dev webpack-cli
  • 全局安装:
    npm install --global webpack webpack-cli
    这个时候文件夹下就有一个package.json和node_modules两个文件

4、打包

  • 默认entry入口 src/index.js
    这时候需要再建个src文件夹,里面间隔入口文件index.js
  • 默认output出口 dist/main.js
  • 打包模式:
    webpack --mode development
    webpack --mode production

 我们将package.json里面的scripts更换成
 “scripts”: {
  “dev”: “webpack --mode development”,
   “build”: “webpack --mode production”
  }
 代表这我们开发和生产两种打包模式。然后我们打包会出现一个dist文件夹,里面是我们打包生成的文件。
5、配置webpack.config.js

  • 新建一个webpack.config.js

  • 配置入口entry(所需打包的文件路径)

    • 单入口

      • 单文件,例如: entry:‘./src/index.js’
      • 多文件:
        在你想要多个依赖文件一起注入,并且将它们的依赖导向到一个“chunk”时,传入数组的方式就很有用。
        例如:entry:[‘./src/index.js’,‘./src/index2.js’,…]。
        单入口多文件一般是将多个文件整合成一个文件,如果你的页面中引用了多个js文件,用webpack就可以将这些js文件整合成一个文件然后引入到页面,这样就可以减少前端资源的请求数。
    • 多入口,例如:
      entry:{
       pageOne: ‘./src/pageOne/index.js’,
       pageTwo: ‘./src/pageTwo/index.js’,
       pageThree: ‘./src/pageThree/index.js’
      }

  • 配置出口output:
    (1)path指文件打包后的存放路径
    (2)path.resolve()方法将路径或路径片段的序列处理成绝对路径
    (3)__dirname 表示当前文件所在的目录的绝对路径
    (4)filename是打包后文件的名称

    • 单出口
      output: {
       path: path.resolve(__dirname, ‘dist’),
       filename: ‘bundle.js’
      }
    • 多出口
      output:{
       path:path.resolve(__dirname,‘dist’),
       filename:’[name].js’
      }

6、配置webpack-dev-server
  webpack-dev-server是webpack官方提供的一个小型Express服务器。使用它可以为webpack打包生成的资源文件提供web服务。webpack-dev-server 主要提供两个功能:
 (1)为静态文件提供服务
 (2)自动刷新和热替换(HMR)

  • 安装: npm install --save-dev webpack-dev-server
  • 配置webpack.config.js文件:
    devServer:{
      contentBase:”./build”, //设置服务器访问的基本目录
      host:‘localhost’, //服务器的ip地址
      port:8080, //端口
      open:true //自动打开页面
    }
  • 配置package.json
    “scripts”: {
       “start”: “webpack-dev-server --mode development”
    }

7、加载css
  loader 让 webpack 能够去处理那些非JavaScript文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。

  npm install style-loader css-loader --save-dev
  在webpack.config.js文件里配置module中的rules
  在 webpack 的配置中 loader 有两个目标:
  test 属性:用于标识出应该被对应的 loader 进行转换的某个或某些文件。
  use 属性:表示进行转换时,应该使用哪个 loader。

   module: {
   rules: [
      {
        test:/.css$/,
       use:[“style-loader”,“css-loader”]
      }
    ]
   }

   并且style-loader必须再前面。
8、less和sass

  • 安装less-loader
    npm install less-loader less --save-dev
    .less文件
@width:10px;
@height :@width + 10px;
#header {
  width: @width;
  height: @height;
}

  配置rules

{
  test:/\.less$/,
  use:["style-loader","css-loader","less-loader"]
}

  注意这时候如果引入css,请保留css-loader,否则将css文件改成less文件。

  • 安装sass-loader
    npm install sass-loader node-sass --save-dev
    .scss文件
$header-color: #f90;
#header {
  $width: 100px;
  width: $width;
  color: $header;
}

  配置rules

{
   test: /\.scss$/,
   use: ["style-loader", "css-loader", "sass-loader"]
 }

9、使用PostCSS处理浏览器前缀
  npm install --save-dev postcss-loader autoprefixer

$header-color: #f90;
#header {
  display: flex;
  $width: 100px;
  width: $width;
  color: $header-color;
}

  配置rules

{
  test: /\.scss$/,
  use: ["style-loader", "css-loader", "sass-loader",{
    loader: "postcss-loader",
    options:{
      plugins:[
        require("autoprefixer")({
          browsers: [
              'ie >= 8', //ie版本大于等于ie8
              'Firefox >= 20', //火狐浏览器大于20版本
              'Safari >= 5', //safari大于5版本
              'Android >= 4', //版本大于Android4
              'Ios >= 6', //版本大于ios6
              'last 4 version' //浏览器最新的四个版本
          ]
        })
      ]
    }
  }]
}

  或者在package.json里加上下图设置:来处理css浏览器前缀

"browserslist": [
  "ie >= 8", 
  "Firefox >= 20", 
  "Safari >= 5", 
  "Android >= 4", 
  "Ios >= 6", 
  "last 4 version" 
]

10、文件处理
  图片处理(再css中使用图片)
  下载安装file-loader
   npm install --save-dev file-loader

{
  test:/\.png|jpg|gif|jpeg$/,
  use: "file-loader"
}

  再来看一下选项配置配置options:
     name:为你的文件配置自定义文件名模板(默认值[hash].[ext])
     context:配置自定义文件的上下文,默认为 webpack.config.js
     publicPath:为你的文件配置自定义 public 发布目录
     outputPath:为你的文件配置自定义 output 输出目录
        [ext]:资源扩展名
        [name]:资源的基本名称
        [path]:资源相对于 context的路径
        [hash]:内容的哈希值

{
  test:/\.png|jpg|gif|jpeg$/,
  use: [{
    loader:"file-loader",
    options:{
      name:"[path][hash]aaa.jpg",
      // context:"../"
      // publicPath:"http://www.abc.com/img",
      outputPath:"./img"
    }
  }]
}

11、字体文件处理
  以bootstrap字体文件为例子
  Boostrap字体文件下载地址:https://v3.bootcss.com/getting-started/
  配置config文件

{
  test: /\.(eot|svg|ttf|woff|woff2)$/,
  use: "file-loader"
}

  打包完成生成的文件有点乱,我们重新配置一下

{
  test: /\.(eot|svg|ttf|woff|woff2)$/,
  use: [{
    loader: "file-loader",
    options: {
      outputPath: "./font"
    }
  }]
}

12、第三方js库处理
  以jquery库为例子
(1)本地导入
  编写配置文件:
  webpack.ProvidePlugin参数是键值对形式,键就是我们项目中使用的变量名,值就是键所指向的库。webpack.ProvidePlugin会先从npm安装的包中查找是否有符合的库。
如果webpack配置了resolve.alias选项(理解成“别名”),那么webpack.ProvidePlugin就会顺着设置的路径一直找下去
  使用webpack.ProvidePlugin前需要引入webpack。

const webpack = require("webpack");

resolve: {
  alias: {
    jQuery:path.resolve(__dirname,"public/js/jquery.min.js")
  }
},
plugins: [
  new webpack.ProvidePlugin({
     $:"jquery"
  })
]

(2)npm安装模块
  安装jquery库:
  npm install jquery --save-dev
  直接在js里import引入, import $ from “jquery”即可。
  另外webpack.ProvidePlugin会先从npm安装的包中查找是否有符合的库。
  我们也可以npm安装jquery,然后不用import,在webpack里面配置

plugins: [
  new webpack.ProvidePlugin({
     $:"jquery"
  })
]

  需要注意的是引入第三方插件的时候这几种方式不要混淆,推荐(2)。
13、编译es6
  目前,ES6(ES2015)这样的语法已经得到很大规模的应用,它具有更加简洁、功能更加强大的特点,实际项目中很可能会使用采用了ES6语法的模块,但浏览器对于ES6语法的支持并不完善。为了实现兼容,就需要使用转换工具对ES6语法转换为ES5语法,babel就是最常用的一个工具。
  babel转化语法所需依赖项:
     babel-loader: 负责 es6 语法转化
     @babel/core: babel核心包
     @babel/preset-env:告诉babel使用哪种转码规则进行文件处理

  npm install babel-loader @babel/core @babel/preset-env --save-dev
  配置config文件
  exclude表示不在指定目录查找相关文件

{
  test: /\.js$/,
  exclude: /node_modules/,
  use: "babel-loader"
}

  新建 .babelrc 文件配置转换规则

{
"presets": ["@babel/preset-env"]
}

  另一种规则配置,也可以不适用.babelrc文件,直接在use中配置即可。

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

14、生成html(html-webpack-plugin)
  HtmlWebpackPlugin会自动为你生成一个HTML文件,根据指定的index.html模板生成对应的 html 文件。
  根据src下的index.html自动在打包后的目录下生成html文件,相关引用关系和文件路径都会按照正确的配置被添加进生成的html里
  npm install html-webpack-plugin --save-dev
  配置config文件

const webpack = require("html-webpack-plugin");
plugins:[
  new HtmlWebpackPlugin({
    template:"./public/index.html",//模板文件路径
    filename:'webpack.html', //生成文件的名称
    minify:{
      minimise:true, //是否打包为最小值
      removeAttributeQuotes:true,//去除引号(不会去除字体图标的引号)
      removeComments:true,//去除注释
      collapseWhitespace:true,//去除空格
      minifyCSS:true,//压缩html内的css
      minifyJS:true,//压缩html内的js
      removeEmptyElements: true,//清理内容为空的元素(不要加,会把字体图标去了)
    },
    hash:true //引入产出资源的时候加上哈希避免缓存
  })
]

15、提取分离css(2种方式),将css移动到指定文件夹下
  将所有的入口 chunk(entry chunks)中引用的 css,移动到独立分离的 CSS 文件
(1)ExtractTextPlugin插件(老插件)
  npm install --save-dev extract-text-webpack-plugin@next
  不加@next会报错
  配置config文件

const ExtractTextPlugin = require("extract-text-webpack-plugin");

  Rules设置:
  fallback:编译后用什么loader来提取css文件

{
  test: /\.css$/,
  // use: ["style-loader", "css-loader"]
  use: ExtractTextPlugin.extract({
    fallback:"style-loader",
    use:"css-loader"
  })
},

  Plugins设置

new ExtractTextPlugin("./css/index.css"),

(2)mini-css-extract-plugin插件
  npm install --save-dev mini-css-extract-plugin
  配置config文件

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

  Rules设置

{
  test: /\.css$/,
  // use: ["style-loader", "css-loader"]
  use: [MiniCssExtractPlugin.loader,"css-loader"]
},

  Plugins设置

new MiniCssExtractPlugin({
  filename: "./css/[name].css"
}),

16、压缩css及优化css结构
  optimize-css-assets-webpack-plugin插件
  npm install --save-dev optimize-css-assets-webpack-plugin
  配置config文件

const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");

  Plugins设置

new OptimizeCssAssetsPlugin({
 assetNameRegExp:/\.css$/g,
 cssProcessor:require("cssnano"),
 cssProcessorPluginOptions:{
   preset:["default",{"discardComments":{removeAll:true}}]
 },
   canPrint:true
})

  assetNameRegExp: 正则表达式,用于匹配需要优化或者压缩的资源名。默认值是 /.css$/g
  cssProcessor: 用于压缩和优化CSS 的处理器,默认是 cssnano.
  cssProcessorPluginOptions:传递给cssProcessor的插件选项,默认为{}
  canPrint:表示插件能够在console中打印信息,默认值是true
  discardComments:去除注释

17、拷贝静态文件
  场景:在项目中未被引入到的项目资源,比如图片,开发文档,保留并和项目打包到一起。将开发的静态资源打包到打包过的文件夹下面。
  npm install --save-dev copy-webpack-plugin
  配置config文件

const CopyWebpackPlugin = require("copy-webpack-plugin");

  Plugins设置

new CopyWebpackPlugin([{
  from:__dirname+"/public/assets",
  to: __dirname + "/build/assets"
}])

  [copy-webpack-plugin] patterns must be an array

18、用clean-webpack-plugin来清除文件
  当我们修改带hash的文件并进行打包时,每打包一次就会生成一个新的文件,而旧的文件并没有删除。
  为了解决这种情况,我们可以使用clean-webpack-plugin在打包之前将文件先清除,之后再打包出最新的文件
  npm install --save-dev clean-webpack-plugin
  配置config文件

const CleanWebpackPlugin = require("clean-webpack-plugin");

  Plugin配置

new CleanWebpackPlugin(["build"])

  先删除build,再重新生成新的build

19、HTML中引入图片
  HTML中引入图片,使用loader时,会出现路径错误,图片不显示的情况,这时我们需要经过loader处理后,图片能正常显示
  cnpm install --save-dev html-loader
  配置config文件
    Rules中配置

{
  test:/\.(html)$/,
  use:{
    loader:"html-loader",
    options:{
      attrs:["img:src","img:data-src"]
    }
  }
}

20、使用sourcemap调试
  Sourcemap是为了解决实际运行代码(打包后的)出现问题时无法定位到开发环境中的源代码的问题。
  devtool选项
    5个基本类型:
    (1) eval
      每个模块都使用 eval() 执行,每一个模块后会增加sourceURL来关联模块处理前后的对应关系。由于会映射到转换后的代码,而不是映射到原始代码(没有从 loader 中获取 source map),所以不能正确的显示行数。因为不需要生成模块的sourcemap,因此打包的速度很快。
    (2) source-map
      source-map会为模块生成独立的soucemap文件。
打包后的模块在模块后面会对应引用一个.map文件,同时在打包好的目录下会生成相应的.map文件。
    (3) Inline
      与source-map不同,增加inline属性后,不会生成独立的.map文件,source map 转换为 DataUrl 后添加到 bundle 中。
    (4) cheap
      cheap属性在打包后同样会为每一个模块生成.map文件,但是与source-map的区别在于cheap生成的.map文件会忽略原始代码中的列信息,也不包含loader的sourcemap。
    (5) module
      包含了loader模块之间的sourcemap,将 loader source map 简化为每行一个映射。
  5种类型可随机搭配。
  使用sourcemap调试
  Js调试

devtool:'source-map',

  Css调试

{
	test: /\.css$/,
	// use: ["style-loader", "css-loader"]
	use: [MiniCssExtractPlugin.loader, "css-loader", {
		loader: "postcss-loader",
		options: {
			plugins: [
				require("autoprefixer")
			],
			sourceMap:true  //在option选项中添加此项
		}
	}]
},
  • 对于开发环境
    cheap-module-eval-source-map
    打包速度不快,但是重新构建速度会很快,不会忽略列信息,同时会包含loader的source map,调试会很清晰,对应到一个行号,包含了4个基本类型。
  • 对于生产环境
    source-map 稳健,完整,也可以不适用。

21、模块热替换
  模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:

  • 保留在完全重新加载页面时丢失的应用程序状态。切换tab栏的时候,在修改css或js的时候,tab的切换状态还是停留在那里,我们的tab的状态不会丢失。
  • 只更新变更内容,以节省宝贵的开发时间。
  • 调整样式更加快速 - 几乎相当于在浏览器调试器中更改样式。

  配置config

devServer: {
  contentBase: './build',  //设置服务器访问的基本目录
  host: 'localhost', //服务器的ip地址
  port: 8080, //端口
  open: true, //自动打开页面
  hot:true
},

  Plugin设置

new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()

  npm run start 可以查看 http://localhost:8080/webpack.html
  但是现在并没有自动替换需要刷新,这是因为我们的热替换只针对有style-loader,应该把我们的提取css的loader更换,修改Js会刷新页面
  devServer中加入hotOnly表示只有热更新,不会自动刷新页面

devServer: {
  contentBase: './build',  //设置服务器访问的基本目录
  host: 'localhost', //服务器的ip地址
  port: 8080, //端口
  open: true, //自动打开页面
  hot: true,
  hotOnly: true
},

  修改js文件时代码不会自动热更新,需加入以下代码可以告诉 webpack 接受更新的模块。

if(module.hot) {
  module.hot.accept()
}

22、区分开发环境和生产环境
  开发环境和生产环境的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载或热模块替换能力 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,以及资源的优化,以改善加载时间。所以我们通常建议为每个环境编写彼此独立的 webpack 配置。
  npm install --save-dev webpack-merge
  可以将公共的配置添加到开发或生产环境中
  拆分文件
  在这里我们可以将webpack.config.js拆分为三个文件,分别是webpack.common.conf.js、webpack.dev.conf.js和webpack.prod.conf.js。

  webpack.common.conf.js是放一些我们公用的配置,比如入口entry、出口output、常用loader以及插件等。
  webpack.dev.conf.js是在开发环境上的配置,比如devServer配置、模块热替换等方便开发的配置。
  webpack.prod.conf.js是在生产环境上的配置,比如提取分离css、压缩css和js等。

  需要注意的是,各个环境下,文件的路径以及生成文件的路径配置需正确,详细配置见源码。

  修改package.json文件中的script

"scripts": {
  "dev": "webpack --mode development --config ./config/webpack.dev.conf.js",
  "build": "webpack --mode production --config ./config/webpack.prod.conf.js",
  "start": "webpack-dev-server --mode development --config ./config/webpack.dev.conf.js"
},

  --config可以指定使用的配置文件

  在webpack的开发环境和生产环境配置中分别在plugins配置

new webpack.DefinePlugin({
  'process.env': {
	NODE_ENV: '"fz"',
	MOCK: 'false',
	}
}),

  打包的时候就会根据process.env.NODE_ENV去区分是什么环境,然后在不同的环境配置不同的接口baseUrl,在请求接口时将这个变量引入到公共部分。

23、删除生产环境的console
  plugins配置

new webpack.optimize.UglifyJsPlugin({
  compress: {
    warnings: false,
    drop_debugger: true,
    drop_console: true
  },
  sourceMap: true
}),

24、webpack打包优化
  优化打包速度
  影响打包速度的元素:文件多,依赖多
  未优化前打包速度是9858ms

Hash: d54dc6c7b8bd740b6853
Version: webpack 4.29.5
Time: 9858ms

(1)减少文件搜索范围
  在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试询问文件是否存在。
  在配置 resolve.extensions 时你需要遵守以下几点,以做到尽可能的优化构建性能:

  • 后缀尝试列表要尽可能的小,不要把项目中不可能存在的情况写到后缀尝试列表中。
  • 频率出现最高的文件后缀要优先放在最前面,以做到尽快的退出寻找过程。
  • 在源码中写导入语句时,要尽可能的带上后缀,从而可以避免寻找过程。例如在你确定的情况下把 require(’./data’) 写成 require(’./data.json’) 。
resolve: {
	extensions:[".js"]
},

(2)优化 resolve.modules 配置
  resolve.modules 用于配置 Webpack 去哪些目录下寻找第三方模块。
  resolve.modules 的默认值是 [‘node_modules’],会采用向上递归搜索的方式查找

function resolve(dir) {
	return path.join(__dirname,"..",dir)
}

__dirname当前路径的绝对路径
path.join([path1][, path2][, …])
用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix系统是"/",Windows系统是""。
path.resolve([from …], to)
将 to 参数解析为绝对路径,给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径。 例如,给定的路径片段的序列为:/foo、/bar、baz,则调用 path.resolve(’/foo’, ‘/bar’, ‘baz’) 会返回 /bar/baz。

resolve: {
	modules:[
		resolve("public"),
		resolve("node_modules")
	]
}

(3)优化resolve.alias配置
  resolve.alias 配置项通过别名来把原导入路径映射成一个新的导入路径。

resolve: {
	alias: {
		"assets": resolve("./public/assets")
	}
}

(4)缩小文件匹配范围
  Include:需要处理的文件的位置
  Exclude:排除掉不需要处理的文件的位置

{
	test: /\.js$/,
	include:[
		resolve("src")
	],
	exclude: /node_modules/,
	use: {
		loader: "babel-loader",
		options: {
			"presets": ["@babel/preset-env"]
		}
	}
}

  这个时候打包

Hash: d54dc6c7b8bd740b6853
Version: webpack 4.29.5
Time: 2977ms

(5)设置noParse
  防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。比如jquery、elementUI等库。

(6)给babel-loader设置缓存
  babel-loader 提供了 cacheDirectory特定选项(默认 false):设置时,给定的目录将用于缓存加载器的结果。

{
	test: /\.js$/,
	include:[
		resolve("public")
	],
	exclude: /node_modules/,
	use: {
		loader: "babel-loader?cacheDirectory=true",
		options: {
			"presets": ["@babel/preset-env"]
		}
	}
},

  设置完成后第一次打包会缓存下来babel-loader,第二次打包会比第一次快很多。

Hash: d54dc6c7b8bd740b6853
Version: webpack 4.29.5
Time: 2811ms

(7)使用happyPack
  happyPack的基本原理:在webpack构建过程中,我们需要使用Loader对js,css,图片,字体等文件做转换操作,并且转换的文件数据量也是非常大的,且这些转换操作不能并发处理文件,而是需要一个个文件进行处理,HappyPack的基本原理是将这部分任务分解到多个子进程中去并行处理,子进程处理完成后把结果发送到主进程中,从而减少总的构建时间。
  cnpm install happypack --save-dev
  配置webpack.common.conf.js文件

const happyPack = require("happypack");

  Rules设置

{
	test: /\.js$/,
	include:[
		resolve("public")
	],
	exclude: /node_modules/,
	loader:"happypack/loader?id=happypackBabel"
}

  Plugins设置

new happyPack({
	id:"happyBabel",
	loaders:[
		{
			loader:"babel-loader"
		}
	]
})

猜你喜欢

转载自blog.csdn.net/qzf_hainenggaima/article/details/88146739