1、webpack的基础操作

目前@vue/cli和create-react-app基本上采用的是webpack4.0以上版本,4版本需要webpack和webpack-cli

安装

  1. npm init -y
  2. npm i webpack@4.44.2 webpack-cli@3.3.11 -D

零配置使用

webpack默认会把当前项目src目录下的文件进行打包编译(默认index.js),编译到dist文件目录下(webpack编译代码的过程中支持CommonJS规范和ES6Module规范)
|- src
当前源代码
|- dist
编译后的文件

  1. npx webpack
  2. 或者script中配置webpack

自己定义webpack打包配置

  1. webpack.config.js OR webpackfile.js

编写自定义的webpack配置项,以后webpack打包编译的时候是按照自己配置的内容进行打包编译处理的(文件根目录)

webpack.config.js

  1. const webpack = require('webpack')
  2. module.exports = {
  3. // 设置编译的入口文件
  4. entry:'src/main.js',
  5. // 设置编译的出口文件
  6. output:{
  7. // 编译后的文件, 添加hash保证编译文件的唯一,清除强缓存
  8. filename: 'bundle.[hash:8].min.js',
  9. path: path.resolve(__dirname,'build')
  10. },
  11. // 设置开发环境还是生产(默认)
  12. mode:'production'
  13. }

强缓存协商缓存,缓存到浏览器,再次访问访问的是存储在本地内存的内容
真实项目中为了在文件更新后,清除强缓存的影响,我们在文件中导入的文件,一般都设置随机数或者不同的HASH值

2、基于自定义配置项打包编译(环境区分)

添加类型声明 提供提醒
yarn add -D @types/webpack

  1. /**
  2. * @type {import('webpack').Configuration}
  3. */

2-1 、区分环境变量,自定义配置文件名

image.png

npx webpack —config webpack —config webpack.config.prod.js

  1. "scripts": {
  2. "serve":"webpack --config webpack.config.dev.js",
  3. "build":"webpack --config webpack.config.prod.js"
  4. }

webpack.config.dev.js

  1. // 开发环境
  2. const path = require('path')
  3. module.exports = {
  4. // 设置编译的入口文件
  5. entry:'./src/main.js',
  6. // 设置编译的出口文件
  7. output:{
  8. // 编译后的文件
  9. filename: 'bundle.js',
  10. path: path.resolve(__dirname,'build')
  11. },
  12. mode:'development'
  13. }

webpack.config.prod.js

  1. // 生产环境
  2. const path = require('path')
  3. module.exports = {
  4. // 设置编译的入口文件
  5. entry:'./src/main.js',
  6. // 设置编译的出口文件
  7. output:{
  8. // 编译后的文件
  9. filename: 'bundle.[hash].min.js',
  10. path: path.resolve(__dirname,'build')
  11. },
  12. }

2-2、 webpack.DefinePlugin 自定义环境变量

  1. module.exports = {
  2. plugins:[
  3. new webpack.DefinePlugin({
  4. DEV: JSON.stringify('production'), // console.log
  5. FLAG:'true',
  6. EXPORESSION: '1+1'
  7. })
  8. ]
  9. }

2-3、webpack-merge 彻底解决生产环境和开发环境的不同配置需求

// webpack.dev.js

  1. let { smart } = require('webpack-merge')
  2. let base = require('./webpack.base.js')
  3. module.exports = smart(base,{
  4. mode: 'development'
  5. })

3、配置HTML页面模版进行打包预览

  • 到目前问题是每一次代码编译后,都需要手动的去修改html页面中指定的带有hash的js文件,不智能化

这时需要一个插件 html-webpack-plugin

  • 是否存在一个插件,可以帮我们创建一个web服务,实现类似live-serve预览的效果

服务可以自动监听代码的改变,自动刷新浏览器看到的最新效果,除了配置项修改了 需要手动执行,其他的都自动化处理 webpack-dev-server

  • 每次打包的时候都需要清除掉之前的打包结果,build下只保留最新的打包文件 clean-webpack-plugin

3-1、html-webpack-plugin

npm i html-webpack-plugin —save-dev

image.png
后面压缩的文件导入到这个页面模版中

  1. const HtmlWebpackPlugin = require('html-webpack-plugin')
  2. plugins:[
  3. new HtmlWebpackPlugin({
  4. // 模版路径
  5. template:"./public/index.html",
  6. // 编译后生成的文件名
  7. filename:"index.html",
  8. // 是否把编译后的资源文件导入页面中都设置HASH(清缓存,和output中设置HASH值是一样的, 和output设置HASH是一样的效果,只要设置一个地方即可)
  9. hash:true,
  10. // 把模版中的HTML代码也进行压缩编译配置 https://github.com/kangax/html-minifier
  11. minify:{
  12. collapseWhitespace:true, // 去除空格
  13. removeComments:true, // 去掉注释
  14. removeAttributeQuotes:true, // 去除属性的双引号
  15. removeEmptyAttributes:true, // 去除空属性
  16. removeEmptyElements:true // 去除空的元素
  17. }
  18. })
  19. ]

在模版中可以自己单独导入一些CSS/JS/图片等资源文件
1、自己导入的文件不受webpack编译的影响(不会和其他模块的文件编译在一起), 所有有时候会单独导入一些公共的资源文件
2、有些资源不支持CommonJS和ESModule规范,只能自己手动导入

3-2、clean-webpack-plugin

npm i webpack-dev-server —save-dev

  1. const { CleanWebpackPlugin }= require('clean-webpack-plugin')
  2. plugins:[
  3. // 每次打包都把之前的清空
  4. new CleanWebpackPlugin('./dist') // 排除 cleanOnceBeforeBuildPatterns: ['!markdown/**/*']
  5. ]

3-3、copy-webpack-plugin 将不参与打包的文件进行拷贝到dist目录下

  1. const CopyWebpackPlugin = require('copy-webpack-plugin')
  2. plugins:[
  3. new CopyWebpackPlugin([{
  4. from:'doc', to:'./'}
  5. ])
  6. ]

3-4、webpack-dev-server

解决跨域 1、代理 2、before函数内mock 3、node里启动

https://webpack.js.org/configuration/dev-server/ npm i webpack-dev-server —save-dev

编译好的结果放在了内存中,不会像webpack一样把编译后的东西放在build下,dev-server仅仅是在开发模式下,随时编译并且预览的,项目部署的时候,还是需要webpack build

  1. // 配置DEV-SERVER 内存中编译打包
  2. devServer: {
  3. before(app){ // 调用内部服务 mock数据
  4. app.get('/user',(req,res)=>{
  5. res.json({name:'rockshang - before'})
  6. })
  7. },
  8. // 端口
  9. port: 3000,
  10. // 开启GZIP压缩
  11. compress: true,
  12. // 显示编译进度
  13. progress:true,
  14. // 指定访问资源目录
  15. contentBase: path.resolve(__dirname,'dist'),
  16. // 自动打开浏览器
  17. open:true,
  18. // 开启热更新
  19. hot:true,
  20. // 请求代理
  21. proxy:{
  22. "/api": {
  23. target:"http://localhost:3000",
  24. pathRewrite: { '/api':'' }, // 重写api 代理到express服务器
  25. // secure: false, // true 为https , false 为http
  26. // changeOrigin: true // 把请求头当中的host值改为服务器地址
  27. }
  28. }
  29. }

启动webpack-dev-server

npx webpack-dev-server

或者脚本中加

  1. "script":{
  2. "serve": "webpack-dev-server"
  3. }
  1. // xhr 请求
  2. let xhr = new XHMLLRequest();
  3. xhr.open('GET','/api/user', true) // 8080 => express => 3000
  4. xhr.onload = function(){
  5. xhr.log(xhr.response);
  6. }
  7. xhr.send();
  8. // node 服务 将webpack在服务端启动
  9. const express = require('express');
  10. const app = express()
  11. const webpack =require('webpack')
  12. // 中间件
  13. const middle = require('webpack-dev-middlewrare')
  14. let config = require('./webpack.config.js')
  15. let compiler = webpack(config)
  16. app.use(middle(compiler))
  17. app.get('/api/user',(req,res)=>{
  18. res.json({name:'rock shang'})
  19. })
  20. app.listen(3000)

3-5、webpack.BannerPlugin 版权插件

  1. let webpack = require('webpack')
  2. plugins:[
  3. new webpack.BannerPlugin('make 2019 by rock')
  4. ]

4、配置多入口的打包编译

多页面的开发,需要配置多个页面入口、多个js入口

chunks 指定当前页面的依赖项,如果多页面都依赖某个js,可以独立打包

webpack.config.js

配置多入口
  1. // entry:'./src/main/js'
  2. // 多入口 KEY:VALUE
  3. entry: {
  4. // 如果不想JQ和其他JS合并在一起,想独立打包可以, 单独引jquery,
  5. // 然后在chunks里面配置jquery,使每个页面都引用
  6. jquery: 'jquery',
  7. index:"./src/main.js",
  8. login:"./src/login.js"
  9. },
  10. output:{ // [name] index.html or login.html
  11. filename:'[name].[hash].min.js',
  12. path:path.resolve(__dirname,'build')
  13. }

配置多页面模版

image.png
webpack.config.js

  1. const htmlPlugins = ['index','login'].map(item=>{
  2. return new new HtmlWebpackPlugin({
  3. template: `./public/${item}.html`,
  4. filename: `${item}.html`,
  5. chunks:['jquery',item], // 设置多入口时的打包的哪个js进来,不写全部引入
  6. minify: {
  7. collapseWhitespace: true, // 去除空格
  8. removeComments: true, // 去掉注释
  9. removeAttributeQuotes: true, // 去除属性的双引号
  10. removeEmptyAttributes: true, // 去除空属性
  11. removeEmptyElements: true,
  12. },
  13. }),
  14. })
  15. module.exports = {
  16. // ...
  17. plugins:[
  18. ...htmlPlugins
  19. ]
  20. }

默认打开的是index.html 页面, 登陆页也已经生成了,只需要输入localhost:3000/login.html
image.png

5、 webpack中的加载器loader: 处理样式的

处理less npm install css-loader style-loader less less-loader autoprefixer postcss-loader —save-dev 处理scss npm i sass node-sass sass-loader css-loader style-loader autoprefixer postcss-loader —save-dev

  1. module.exports = {
  2. // 配置模块加载器LOADER
  3. //...
  4. moudule: {
  5. // 模块规则,使用加载器,从右向左执行,从下向上执行
  6. rules:[{
  7. test: /\.(css|less)$/i, // 基于正则处理
  8. use:[
  9. "style-loader", // css插入到HEAD中,内嵌式加入
  10. "css-loader", // 编译解析@import/URL这种语法
  11. "postcess-loader", // 设置前缀,兼容css3写法, 需要搭配autoprefixer一起使用,需要额外配置
  12. {
  13. loader:"less-loader",
  14. options:{
  15. // 加载器额外配置
  16. }
  17. }
  18. ]
  19. }]
  20. },
  21. //...
  22. }

postcss.config.js

  1. module.exports = {
  2. plugins:[
  3. require('autoprefixer')
  4. ],
  5. }

package.json —— 处理浏览器的兼容列表

  1. // https://github.com/browserslist/browserslist
  2. "browserslist":[
  3. "> 1%", // 兼容百分之99的浏览器
  4. "last 2 versions" // 兼容最近两个版本的浏览器
  5. ],

可以在页面中直接引用但是会发http请求,真实项目中,入口文件中会应用项目所需要的大部分资源

  • 样式资源
  • JS资源
  • 各种模块

在入口处引入,webpack会根基资源文件的依赖关系全部合到一起
import ‘./static/css/index.css’

6、mini-css-extract-plugin 抽离CSS内容 改内嵌为外链式

https://www.npmjs.com/package/mini-css-extract-plugin npm i mini-css-extract-plugin —save-dev

webpack.config.js

  1. const MiniCssExtractPlugin = require('mini-css-extract-plugin')
  2. module.exports = {
  3. //...
  4. plugins:[
  5. // 使用插件
  6. new MiniCssExtractPlugin({
  7. falename: '[name].[hash].min.css'
  8. })
  9. ]
  10. //...
  11. module:{
  12. rules:[{
  13. //替换 "style-loader",
  14. MiniCssExtractPlugin.loader,
  15. "css-loader",
  16. "postcss-loader",
  17. "less-loader"
  18. }]
  19. },
  20. //...
  21. }

7、 设置优化压缩CSS/JS

安装

npm i optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin terser-webpack-plugin -D

webpack.config.js

  1. const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
  2. // const TerserPlugin = require('terser-webpack-plugin');
  3. const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
  4. module.exports = {
  5. // ...
  6. // 设置优化项
  7. optimization:{
  8. // 设置压缩方式
  9. minimizer:[
  10. //=> 压缩CSS(但是必须指定JS压缩方式)
  11. new OptimizeCssAssetsWebpackPlugin(),
  12. //=> 压缩JS 下面两个用一个即可
  13. new UglifyjsWebpackPlugin({
  14. cache:true, // 是否使用缓存
  15. parallel:true, // 是否是并发编译
  16. sourceMap:true // 启动远吗映射 (方便调试)
  17. }),
  18. // new TerserPlugin()
  19. ]
  20. },
  21. //...
  22. }

8、webpack中处理图片资源、字体图标(优化压缩)

npm i file-loader url-loader html-withimg-loader -D

webpack.config.js

  1. module.exports = {
  2. //...
  3. module: {
  4. rules: [
  5. //...
  6. {
  7. test:/\.(png|jpe?g|gif|ico|bmp|svg|eot|ttf|woff|woff2)$/i,
  8. use:[{
  9. // 把指定图片大小内的图片BASE64
  10. // 不再指定范围的采用file-loader进行处理
  11. // 符合规则的用url-loader处理,不符合的仍然用file-loader处理
  12. loader:'url-loader',
  13. options:{
  14. limit: 200 * 1024, // 小于200kb处理成BASE64
  15. // outputPath:'./images', // 图片编译后都放在统一的images文件下
  16. name:'images/[name].[hash].[ext]',
  17. esModule: false
  18. }
  19. }],
  20. include: path.resolve(__dirname,'src'),
  21. exclude: /node_modules/
  22. },
  23. // 处理HTML页面中的图片,按照上面的处理机制处理
  24. {
  25. test:/\.html$/,
  26. use:['html-withimg-loader']
  27. }
  28. //...
  29. ]
  30. }
  31. }

真实项目中使用图片的地方

  • CSS中设置背景图

    1. body{
    2. backgroundImage:url(./image/xxx.png) norepeat;
    3. }
  • JS中动态创建图片

    如果网络地址直接写 如果相对地址,需要require导入否则找不到

  1. let A = require('./static/play.png')
  2. let image = new Image;
  3. image.src = require('./static/play.png')
  4. document.body.appendChild(image)
  • HTML中直接使用图片
    1. <img src="./image/xxx.png"/>

9、三种方式引入第三方模块 expose-loader

  1. 1. expose-loader暴露全局window => import $ from 'expose-loader?$!jQuery'
  2. 2. providePlugin给每个人提供一个$ =>
  3. plugins:[
  4. new webpack.ProvidePlugin({ // 在每个模块中都注入$
  5. $: 'jquery'
  6. }) ]
  7. 3. 引入但是不加到打包后的文件中去
  8. externals: { // 引入cdn jquery 不打包jquery
  9. 'jquery':'$'
  10. }

10、基于babel实现ES6的转换和ESLint语法检测

文档 https://babeljs.io/ https://eslint.org/ 安装 npm i babel-loader @babel/core @babel/preset-env -D npm i @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime-D npm i @babel/runtime @babel/polyfill -S npm i eslint-loader -D

默认情况下,webpack只是把各版本的代码合并压缩,对于JS并没有左其他处理,并没有兼容ES6等,需要额外处理 => babel
webpack.config.js

  1. module.exports = {
  2. //...
  3. module: {
  4. rules: [
  5. // 处理JS
  6. //...
  7. {
  8. test: /\.(jsx?)$/i,
  9. use: [
  10. {
  11. loader: 'babel-loader',
  12. options: {
  13. presets: [
  14. '@babel/preset-env', //=> ES6 转成 ES5
  15. '@babel/preset-react' //=> 支持 React
  16. ],
  17. //=> 基于插件处理ES6、ES7中的CLASS的特殊语法
  18. plugins: [
  19. [
  20. '@babel/plugin-proposal-decorators',{ legacy: true },
  21. ],
  22. [
  23. '@babel/plugin-proposal-class-properties', { loose: true },
  24. ],
  25. '@babel/plugin-transform-runtime',
  26. ],
  27. },
  28. },
  29. // 开启语法检测
  30. "eslint-loader"
  31. ],
  32. include: path.resolve(__dirname, 'src'),
  33. exclude: /node_modules/,
  34. },
  35. //...
  36. ]
  37. }
  38. }

main.js

  1. let [a,b] = [10,20];
  2. console.log(a,b)

11、设置sourceMap

  1. // 增加映射文件,帮我们调试源代码
  2. devtool: 'source-map' // 产生单独文件, 增加映射,告诉我们错误的行和列 大和全
  3. devtool: 'eval-source-map' // 不会产生单独的文件,但是可以找到错误的行和列
  4. devtool: 'cheap-module-source-map' // 产生文件 不会找到行列
  5. devtool: 'cheap-module-eval-source-map' // 不产生文件 找到行 不找列
  6. // 开发环境推荐
  7. module.exports = {
  8. devtool: 'cheap-module-eval-source-map'
  9. }
  10. // 生产环境推荐
  11. module.exports = {
  12. devtool: 'cheap-module-source-map'
  13. }

12、 watch监控

实时打包 监控文件 ,每次可以看打包出来的文件 devServer打包的在内存没发看到

  1. module.exports = {
  2. watch: true,
  3. watchOptions:{
  4. poll: 1000, // 每秒询问一下是不是更新
  5. aggreatment: 500, // 防抖 一致输入代码 打包
  6. ignored: /node_modules/ // 忽略哪个文件不监控
  7. }
  8. }

12、 resolve设置 解析第三方包

  1. module.exports = {
  2. resolve:{
  3. modules: [path.resolve('node_moudles')],
  4. // 扩展名 此时在引入可以不加后缀名
  5. extensions:['.js','.css','.vue'],
  6. // mainFiels:['style','main'],
  7. // mainFiles:[], // 入口文件的名字 index.js
  8. alias: { // 别名 vue ...
  9. bootstrap: 'bootstrap/dist/css/bootstrap.css'
  10. }
  11. }
  12. }

13、 快速开发

初始化
  1. npm init -y
  2. npm i webpack@4.44.2 webpack-cli@3.3.11 -D

安装
  1. npm i html-webpack-plugin --save-dev
  2. npm i webpack-dev-server --save-dev
  3. npm i clean-webpack-plugin --save-dev
  4. npx webpack-dev-server
  5. npm install css-loader style-loader less less-loader autoprefixer postcss-loader --save-dev
  6. npm i mini-css-extract-plugin --save-dev
  7. npm i optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin terser-webpack-plugin -D
  8. npm i file-loader url-loader html-withimg-loader -D
  9. npm i babel-loader @babel/core @babel/preset-env -D
  10. npm i @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime -D
  11. npm i @babel/runtime @babel/polyfill -S
  12. npm i eslint-loader -D
  13. npm i expose-loader -D

webpack.config.js
  1. const path = require('path');
  2. const HtmlWebpackPlugin = require('html-webpack-plugin');
  3. const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  4. const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  5. const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
  6. const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
  7. const htmlPlugins = ['index', 'login'].map((item) => {
  8. return new HtmlWebpackPlugin({
  9. template: `./public/${item}.html`,
  10. filename: `${item}.html`,
  11. chunks: [item], // 设置多入口时的打包的哪个js进来,不写全部引入
  12. minify: {
  13. collapseWhitespace: true, // 去除空格
  14. removeComments: true, // 去掉注释
  15. removeAttributeQuotes: true, // 去除属性的双引号
  16. removeEmptyAttributes: true, // 去除空属性
  17. removeEmptyElements: true,
  18. },
  19. });
  20. });
  21. module.exports = {
  22. // 设置编译的入口文件
  23. mode: 'production',
  24. devtool: 'cheap-module-eval-source-map'
  25. // entry: './src/main.js',
  26. entry: {
  27. // jquery: 'jquery',
  28. index: './src/main.js',
  29. login: './src/login.js',
  30. },
  31. // 设置编译的出口文件
  32. output: {
  33. // 编译后的文件
  34. filename: '[name].[hash].min.js',
  35. path: path.resolve(__dirname, 'build'),
  36. },
  37. // 配置devServer
  38. devServer: {
  39. // 端口
  40. port: 3000,
  41. // 开启GZIP压缩
  42. compress: true,
  43. // 显示编译进度
  44. progress: true,
  45. // 指定访问资源目录
  46. contentBase: path.resolve(__dirname, 'build'),
  47. // 自动打开浏览器
  48. open: true,
  49. // 开启热更新
  50. hot: true,
  51. // 请求代理
  52. // proxy: {
  53. // '/': {
  54. // target: 'http://localhost:8888',
  55. // secure: false, // true 为https , false 为http
  56. // changeOrigin: true, // 把请求头当中的host值改为服务器地址
  57. // },
  58. // },
  59. },
  60. // 设置优化项
  61. optimization: {
  62. // 设置压缩方式
  63. // minimize: true,
  64. minimizer: [
  65. //=> 压缩CSS(但是必须指定JS压缩方式)
  66. new OptimizeCssAssetsWebpackPlugin(),
  67. //=> 压缩JS 下面两个用一个即可
  68. new UglifyjsWebpackPlugin({
  69. cache: true, // 是否使用缓存
  70. parallel: true, // 是否是并发编译
  71. sourceMap: true, // 启动远吗映射 (方便调试)
  72. })
  73. ],
  74. },
  75. module: {
  76. // 模块规则,使用加载器,从右向左执行,从下向上执行
  77. rules: [
  78. // 处理CSS
  79. {
  80. test: /\.(css|less)$/i, // 基于正则处理
  81. use: [
  82. // 'style-loader', // css插入到HEAD中
  83. MiniCssExtractPlugin.loader, // 处理less的文件 使用插件的loader,抽离css
  84. 'css-loader', // 编译解析@import/URL这种语法
  85. 'postcss-loader', // 设置前缀,兼容css3写法
  86. {
  87. loader: 'less-loader',
  88. options: {
  89. // 加载器额外配置
  90. },
  91. },
  92. ],
  93. },
  94. // 处理图片
  95. {
  96. test: /\.(png|jpe?g|gif|ico|bmp|svg|eot|ttf|woff|woff2)$/i,
  97. use: [
  98. {
  99. // 把指定图片大小内的图片BASE64
  100. // 不再指定范围的采用file-loader进行处理
  101. // 符合规则的用url-loader处理,不符合的仍然用file-loader处理
  102. loader: 'url-loader',
  103. options: {
  104. limit: 1 * 1024, // 小于200kb处理成BASE64
  105. outputPath: './images', // 图片编译后都放在统一的images文件下
  106. name: '[name].[hash].[ext]',
  107. esModule: false,
  108. // publicPath: 'http://www.rockshang.cn' // 加CDN前缀
  109. },
  110. },
  111. ],
  112. include: path.resolve(__dirname, 'src'),
  113. exclude: /node_modules/,
  114. },
  115. // 处理HTML页面中的图片,按照上面的处理机制处理
  116. {
  117. test: /\.html$/,
  118. use: ['html-withimg-loader'],
  119. },
  120. // 处理JS
  121. {
  122. test: /\.(jsx?)$/i,
  123. use: [
  124. {
  125. loader: 'babel-loader',
  126. options: {
  127. presets: [
  128. //=> ES6 转成 ES5
  129. '@babel/preset-env',
  130. ],
  131. //=> 基于插件处理ES6、ES7中的CLASS的特殊语法
  132. plugins: [
  133. [
  134. '@babel/plugin-proposal-decorators',
  135. {
  136. legacy: true,
  137. },
  138. ],
  139. [
  140. '@babel/plugin-proposal-class-properties',
  141. {
  142. loose: true,
  143. },
  144. ],
  145. '@babel/plugin-transform-runtime',
  146. ],
  147. },
  148. },
  149. // 开启语法检测
  150. "eslint-loader"
  151. ],
  152. include: path.resolve(__dirname, 'src'),
  153. exclude: /node_modules/,
  154. },
  155. ],
  156. },
  157. externals: { // 引入cdn jquery 不打包jquery
  158. 'jquery':'$'
  159. }
  160. plugins: [
  161. new webpack.ProvidePlugin({ // 在每个模块中都注入$
  162. $: 'jquery'
  163. }),
  164. // new HtmlWebpackPlugin({
  165. // // 模版路径
  166. // template: './public/index.html',
  167. // // 编译后生成的文件名
  168. // filename: 'index.html',
  169. // // 是否把编译后的资源文件导入页面中都设置HASH(清缓存,和output中设置HASH值是一样的, 和output设置HASH是一样的效果,只要设置一个地方即可)
  170. // // hash: true, // 和output的HASH设置,设置一个即可
  171. // // 把模版中的HTML代码也进行压缩编译配置
  172. // // https://github.com/kangax/html-minifier
  173. // minify: {
  174. // collapseWhitespace: true, // 去除空格
  175. // removeComments: true, // 去掉注释
  176. // removeAttributeQuotes: true, // 去除属性的双引号
  177. // removeEmptyAttributes: true, // 去除空属性
  178. // removeEmptyElements: true,
  179. // },
  180. // }),
  181. // 多入口文件的处理
  182. ...htmlPlugins,
  183. new CleanWebpackPlugin(),
  184. new MiniCssExtractPlugin({
  185. filename: '[name].[hash].min.css',
  186. }),
  187. ],
  188. };

package.json

  1. {
  2. "name": "weback",
  3. "version": "1.0.0",
  4. "description": "",
  5. "main": "index.js",
  6. "scripts": {
  7. "test": "echo \"Error: no test specified\" && exit 1",
  8. "serve": "webpack-dev-server",
  9. "build": "webpack --config webpack.config.js",
  10. "dev": "webpack --config webpack.config.dev.js",
  11. "prod": "webpack --config webpack.config.prod.js"
  12. },
  13. "keywords": [],
  14. "author": "",
  15. "license": "ISC",
  16. "devDependencies": {
  17. "@babel/core": "^7.12.9",
  18. "@babel/preset-env": "^7.12.7",
  19. "autoprefixer": "^10.0.3",
  20. "babel-loader": "^8.2.2",
  21. "clean-webpack-plugin": "^3.0.0",
  22. "css-loader": "^5.0.1",
  23. "eslint-loader": "^4.0.2",
  24. "file-loader": "^6.2.0",
  25. "html-webpack-plugin": "^4.5.0",
  26. "html-withimg-loader": "^0.1.16",
  27. "less": "^3.12.2",
  28. "less-loader": "^7.1.0",
  29. "mini-css-extract-plugin": "^1.3.1",
  30. "optimize-css-assets-webpack-plugin": "^5.0.4",
  31. "postcss-loader": "^4.1.0",
  32. "style-loader": "^2.0.0",
  33. "terser-webpack-plugin": "^5.0.3",
  34. "uglifyjs-webpack-plugin": "^2.2.0",
  35. "url-loader": "^4.1.1",
  36. "webpack": "^4.44.2",
  37. "webpack-cli": "^3.3.11",
  38. "webpack-dev-server": "^3.11.0"
  39. },
  40. "browserslist": [
  41. "> 0.1%",
  42. "last 10 versions"
  43. ],
  44. "dependencies": {
  45. "@babel/polyfill": "^7.12.1",
  46. "@babel/runtime": "^7.12.5"
  47. }
  48. }

postcss.config.js
  1. module.exports = {
  2. plugins:[
  3. require('autoprefixer')
  4. ]
  5. }

项目结构

image.png

14、webpack的优化

14-1、 noParse 不去匹配依赖项 如jQuery , exclude排除node_modules

  1. const path = require('path');
  2. module.exports = {
  3. mode: 'production',
  4. entry: './src/main.js',
  5. // 设置编译的出口文件
  6. output: {
  7. // 编译后的文件
  8. filename: '[name].[hash].min.js',
  9. path: path.resolve(__dirname, 'build'),
  10. },
  11. module: {
  12. noParse:/jQuery/, // 不去解析jQuery
  13. rules: [
  14. // 处理JS
  15. {
  16. test: /\.(jsx?)$/i,
  17. use: [
  18. {
  19. loader: 'babel-loader',
  20. options: {
  21. presets: [
  22. '@babel/preset-env',
  23. '@babel/preset-react'
  24. ],
  25. },
  26. }
  27. ],
  28. include: path.resolve(__dirname, 'src'),
  29. exclude: /node_modules/,
  30. },
  31. ],
  32. },
  33. plugins: [
  34. ],
  35. };

14-2、 webpack.IgnorePlugin(/.\/locale/,/moment/) 忽略某些包

  1. import 'moment/locale/zh-cn' // 手动引入中文包
  2. plugins: [
  3. new webpack.IgnorePlugin(/\.\/locale/,/moment/) // 忽略这个包
  4. ],

14-3、 DLLReferencePlugin 动态链接库

先去查找清单,没有再去打包react,react-dom @babel/preset-react

动态链接库,不用每次打包react,react库 , 大大提高开发效率
使用动态链接库 优化本地webpack打包体验

package.json

  1. "dll": "npx webpack --config webpack.dll.config.js"

import React from ‘react’ import ReactDOM from ‘react-dom’,

ReactDOM.render(

hello world

)

webpack.config.react.js

  1. let path = require('path')
  2. let webpack = require('webpack')
  3. module.exports = {
  4. mode:'development',
  5. entry:{
  6. react:['react','react-dom']
  7. },
  8. output:{
  9. filename:'_dll_[name].js', // 产生的文件名
  10. path:path.resolve(__dirname,'dist/dll'),
  11. library:'_dll_[name]', // _dll_react
  12. // libraryTarget:'var' // commonjs umd var this
  13. },
  14. plugins:[
  15. new webpack.DllPlugin({
  16. name:'_dll_[name]',
  17. path:path.resolve(__dirname,'dist/dll','manifest.json')
  18. })
  19. ]
  20. }

在html文件中引入

  1. <script src="/_dll_react.js"></script>

先去链接库找,找不到在去打包

webpack配置 webpack.config.js

  1. plugins:[
  2. new webpack.DllReferencePlugin({
  3. manifest: path.resolve(__dirname,'dist','manifest.json')
  4. })
  5. ]

14-4、 happypack 可以实现多线程 来打包 进程

npm i happypack

  1. let Happypack = require('happypack')
  2. module.exports = {
  3. //...
  4. module: {
  5. rules: [
  6. // 处理JS
  7. //...
  8. {
  9. test: /\.js$/,
  10. include: path.resolve(__dirname, 'src'),
  11. exclude: /node_modules/,
  12. use: 'Happypack/loader?id=js',
  13. },
  14. {
  15. test: /\.css$/,
  16. include: path.resolve(__dirname, 'src'),
  17. exclude: /node_modules/,
  18. use: 'Happypack/loader?id=css',
  19. },
  20. //...
  21. ]
  22. },
  23. plugins:[
  24. new Happypack({
  25. id:'js',
  26. use:[{
  27. loader: 'babel-loader',
  28. options: {
  29. presets: [
  30. '@babel/preset-env',
  31. '@babel/preset-react'
  32. ]
  33. }
  34. }]
  35. }),
  36. new Happypack({
  37. id:'css',
  38. use:['style-loader','css-loader']
  39. })
  40. ]
  41. }

14-5、 webpack自带的优化

1、 tree-shaking 把没用的代码自动删除上 只能import语法

let sum = (a,b) => a + b + ‘sum’ let minus = (a,b) => a - b + ‘minus’ export { sum , minus }

import calc from ‘./test’

2、 scope hosting 作用域提升
在webpack中会自动省略一些可以简化的代码,将一些计算提前计算,简化一些代码

let a =1 , b =3, c =3 ,d =a+b+c; console.log(d,’——-‘)

14-6、提取公共代码 splitChunks

webpack.config.js

  1. optimization:{ // 优化项
  2. splitChunks:{ // 分割代码块 多页!
  3. cacheGroups:{ // 缓存组
  4. common:{ // 公共的模块
  5. chunks:'initial',
  6. minSize:0, // 大小
  7. minChunks:2 // 用了多少次
  8. },
  9. vendor:{ // 抽离第三方模块 如jQuery
  10. priority:1, // 提高抽离权重,先抽离这个模块
  11. test:/node_modules/, // 把抽象代码抽离
  12. chunks:'initial',
  13. minSize:0, // 大小
  14. minChunks:2 // 用了多少次
  15. }
  16. }
  17. }
  18. }

14-7、懒加载 靠的就是import语法

点击按钮在加载资源

npm i @babel/plugin-syntax-dynamic-import -D 加到插件预设里

  1. export default 'xxxxyyyy1111'
  2. let button = document.createElement('button')
  3. button.addEventListener('click',function(){
  4. // es6 草案语法
  5. import('./source.js').then(data=>{
  6. console.log(data.default)
  7. })
  8. })

14-8、热更新插件

webpack.config.js

  1. devServer:{
  2. hot:true, // 启动热更新
  3. port: 3000,
  4. open: true,
  5. contentBase: './dist'
  6. }
  7. ...
  8. plugins:[
  9. new webpack.NamedModulesPlugin(), // 打印更新的模块路径
  10. new webpack.HotModuleReplacementPlugin() // 热更新插件
  11. ]

index.js

  1. // source.js
  2. export default 'ssss'
  3. // index.js
  4. import str from './source';
  5. console.log(str)
  6. if(module.hot){
  7. module.hot.accept('./source',()=>{
  8. require('./source')
  9. console.log('文件更新了')
  10. })
  11. }

14-9、PWA 离线应用

webpack.config.js

  1. 6PWA 离线技术访问
  2. ```js
  3. //webpack.config.js
  4. const WorkboxWebpackPlugin = require("workbox-webpack-plugin");
  5. plugins: [
  6. new MiniCssExtractPlugin({
  7. filename: "css/style.[contenthash:10].css",
  8. }),
  9. new OptimizeCssAssetsWebpackPlugin(),
  10. new htmlWebpackPlugin({
  11. filename: "index.html",
  12. template: "./public/index.html",
  13. minify: {
  14. //压缩html
  15. collapseWhitespace: true,
  16. removeComments: true,
  17. },
  18. }),
  19. new WorkboxWebpackPlugin.GenerateSW({
  20. clientsClaim: true, //帮助service-worker快速启动
  21. skipWaiting: true, //删除旧的service-worker
  22. //生成service-workder.js
  23. }),
  24. ];
  25. //入口文件
  26. if ("serviceWorker" in navigator) {
  27. window.addEventListener("load", () => {
  28. navigator.serviceWorker
  29. .register("./service-worker.js")
  30. .then(() => {
  31. console.log("service注册成功了~");
  32. })
  33. .catch(() => {
  34. console.log("service注册失败了~");
  35. });
  36. });
  37. }

```