ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

webpack4学习

2020-04-05 13:59:08  阅读:217  来源: 互联网

标签:use webpack4 module js 学习 webpack loader css


一.安装前先npm初始化

1 npm init -y
2 npm i webpack webpack-cli -D

创建webpack.config.js文件

let path = require('path')   // 相对路径变绝对路径

module.exports = {
  mode: 'production', // 模式 默认 production development
  entry: './src/index',    // 入口
  output: {
    filename: 'bundle.[hash:8].js',   // hash: 8只显示8位
    path: path.resolve(__dirname, 'dist'),
    publicPath: ''  // // 给所有打包文件引入时加前缀,包括css,js,img,如果只想处理图片可以单独在url-loader配置中加publicPath
  }
}

二.本地服务

npm i webpack-dev-server -D
devServer: {
  port: 3000,
  progress: true          // 滚动条
  contentBase: './build'  // 起服务的地址
  open: true              // 自动打开浏览器
  compress: true         // gzip压缩
}

三.处理html

npm i html-webpack-plugin -D
let HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [ // 放着所有webpack插件
  new HtmlWebpackPlugin({ // 用于使用模板打包时生成index.html文件,并且在run dev时会将模板文件也打包到内存中
    template: './index.html', // 模板文件
    filename: 'index.html', // 打包后生成文件
    hash: true, // 添加hash值解决缓存问题
    minify: { // 对打包的html模板进行压缩
      removeAttributeQuotes: true, // 删除属性双引号
      collapseWhitespace: true // 折叠空行变成一行
    }
  })
] 

html-webpack-plugin#options

四.处理css

npm i css-loader style-loader -D
// css-loader   作用:用来解析@import这种语法
// style-loader 作用:把 css 插入到head标签中
// loader的执行顺序: 默认是从右向左(从下向上)
module: {    // 模块
  rules: [   // 规则
    // style-loader 把css插入head标签中
    // loader 功能单一
    // 多个loader 需要 []
    // 顺便默认从右到左
    // 也可以写成对象方式
    {
      test: /\.css$/,   // css 处理
      // use: 'css-loader'
      // use: ['style-loader', 'css-loader'],
      use: [
        // {
        //     loader: 'style-loader',
        //     options: {
        //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
        //     }
        // },
        MiniCssExtractPlugin.loader,
        'css-loader', // css-loader 用来解析@import这种语法,
        'postcss-loader'
      ]
    }
  ]
}

五.处理less等

npm i less-loader
{
  test: /\.less$/,   // less 处理
  // use: 'css-loader'
  // use: ['style-loader', 'css-loader'],
  use: [
    // {
    //     loader: 'style-loader',
    //     options: {
    //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
    //     }
    // },
    MiniCssExtractPlugin.loader,   // 这样相当于抽离成一个css文件, 如果希望抽离成分别不同的css, 需要再引入MiniCssExtractPlugin,再配置
    'css-loader', // css-loader 用来解析@import这种语法
    'postcss-loader',
    'less-loader' // less-loader less -> css
    // sass node-sass sass-loader
    // stylus stylus-loader
  ]
}

less-loader

六.抽离css文件,通过link引入

yarn add mini-css-extract-plugin -D
let MiniCssExtractPlugin = require('mini-css-extract-plugin')

// 压缩css

plugins: [
  new MiniCssExtractPlugin({
      filename: 'css/main.css'
  })
]

{
  test: /\.css$/,   // css 处理
  // use: 'css-loader'
  // use: ['style-loader', 'css-loader'],
  use: [
    // {
    //     loader: 'style-loader',
    //     options: {
    //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
    //     }
    // },
    // 此时不需要style-loader
    MiniCssExtractPlugin.loader,   // 抽离
    'css-loader', // css-loader 用来解析@import这种语法,
    'postcss-loader'
  ]
}

 mini-css-extract-plugin

1.压缩css和js

// 用了`mini-css-extract-plugin`抽离css为link需使用`optimize-css-assets-webpack-plugin`进行压缩css,使用此方法压缩了css需要`uglifyjs-webpack-plugin`压缩js
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")
const UglifyJsPlugin = require("uglifyjs-webpack-plugin")

module.exports = {
  optimization: {              // 优化项
    minimizer: [
      new UglifyJsPlugin({     // 优化js
        cache: true,           // 是否缓存
        parallel: true,        // 是否并发打包
        // sourceMap: true     // 源码映射 set to true if you want JS source maps
      }),
      new OptimizeCSSAssetsPlugin({})    // css 的优化
    ]
  },
  mode: 'production',
  entry: '',
  output: {},
}

 

七.给css加上兼容浏览器的前缀

yarn add postcss-loader autoprefixer -D
// css
{
  test: /\.css$/,   // css 处理
  // use: 'css-loader'
  // use: ['style-loader', 'css-loader'],
  use: [
    // {
    //     loader: 'style-loader',
    //     options: {
    //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
    //     }
    // },
    MiniCssExtractPlugin.loader,
    'css-loader', // css-loader 用来解析@import这种语法,
    'postcss-loader'
  ]
}
// less
{
  test: /\.less$/,   // less 处理
  // use: 'css-loader'
  // use: ['style-loader', 'css-loader'],
  use: [
    // {
    //     loader: 'style-loader',
    //     options: {
    //         insertAt: 'top' // 将css标签插入最顶头  这样可以自定义style不被覆盖
    //     }
    // },
    MiniCssExtractPlugin.loader,   // 这样相当于抽离成一个css文件, 如果希望抽离成分别不同的css, 需要再引入MiniCssExtractPlugin,再配置
    'css-loader', // css-loader 用来解析@import这种语法
    'postcss-loader',
    'less-loader' // less-loader less -> css
    // sass node-sass sass-loader
    // stylus stylus-loader
  ]
},

postcss 需要配置文档 postcss.config.js

postcss-loader

module.exports = {
  plugins: [
    require('autoprefixer')
  ]
}

 

八.es6 转 es5

npm i babel-loader @babel/core @babel/preset-env -D
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [ //预设
              '@babel/preset-env' 
            ],
            plugins:[
              // 转es7的语法
              ["@babel/plugin-proposal-decorators", { "legacy": true }],
              ["@babel/plugin-proposal-class-properties", { "loose" : true }]
            ]
          }
        },
        exclude: /node_modules/
      }
    ]
  }
}

 

1.转es7的语法

// 转class
npm i @babel/plugin-proposal-class-properties -D

// 转装饰器
npm i @babel/plugin-proposal-decorators -D

 

2.其他不兼容的高级语法

使用 @babel/polyfill

 

3.语法检查 eslint

npm i eslint eslint-loader -S

 

根目录添加 .eslintrc.json 配置文件

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'eslint-loader',
          options: {
            enforce: 'pre'  // previous优先执行  post-普通loader之后执行
          }
        }
      },
      {
        test: /\.js$/,      // mormal 普通的loader
        use: {
          loader: 'babel-loader',
          options: {
            presets: [ //预设
              '@babel/preset-env' 
            ]
          }
        },
        exclude: /node_modules/
      }
    ]
  }
}

 

九.全局变量引入第三方库(jq)

npm i jquery -S
let webpack = require('webpack')

new webpack.ProvidePlugin({
  $: 'jquery'
})

 

1.暴露全局

npm i expose-loader -D 暴露全局的loader

 

a. 

可以在js中 

import $ from 'expose-loader?$!jquery' // 全局暴露jquery为$符号 

可以调用window.$

b.

 也可在webpack.config.js 中配置 rules

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve('jquery'),
        use: 'expose-loader?$'
      }
    ]
  }
}

 

以后在.js文件中引入

import $ from 'jquery'

 

c.

如何在每个模块中注入:

let webpack = require('webpack')

module.exports = {
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery'
    })
  ]
}

之后代码内直接使用 $

 

d.

index.html中通过script标签引入jquery, 但是在js中,用import会重新打包jquery,如何避免

从输出的bundle 中排除依赖

module.exports = {
  externals: { // 告知webpack是外部引入的,不需要打包
    jquery: 'jQuery'
  }
}

 

此时在index.js上

import $ from 'jquery'

console.log($)

 

十.webpack图片打包处理

1.js中创建

2.css中引入

3.<img src="">

yarn add file-loader -D 适合一二情况
module.export={
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif)$/,
        use: 'file-loader'
      }
    ]
  }
}

 

默认会内部生成一张图片到build,生成图片的路径返回回来

第一种情况: 图片地址要import引入,直接写图片的地址,会默认为字符串

import logo from './logo.png'

let image = new Image()
image.src = logo
document.body.appendChild(image)

 

第二种情况: css-loader会将css里面的图片转为require的格式

div {
  background: url("./logo.png");
}

 

第三种情况: 解析html中的image

{
  test: /\.html$/,
  use: 'html-withimg-loader'
}
yarn add html-withimg-loader -D

 

4. 当图片小于多少,用base64

yarn add url-loader -D  如果过大,才用file-loader
{
  test: /\.(png|jpg|gif)$/,
  // 当图片小于多少,用base64,否则用file-loader产生真实的图片
  use: {
    loader: 'url-loader',
    options: {
      limit: 200 * 1024,          // 小于200k变成base64
      // outputPath: '/img/',     // 打包后输出地址
      // publicPath: ''           // 给资源加上域名路径
    }
  }

 

十一.打包文件分类和多页面

1.图片

{
  test: /\.(png|jpg|gif)$/,
  // 当图片小于多少,用base64,否则用file-loader产生真实的图片
  use: {
    loader: 'url-loader',
    options: {
      limit: 1,  // 200k 200 * 1024
      outputPath: 'img/'   // 打包后输出地址 在dist/img
    }
  }
},

 

2.css

plugins: [
  new MiniCssExtractPlugin({
    filename: 'css/main.css'
  }),
]

 

3.希望输出的时候,给这些css\img加上前缀,传到服务器也能访问

output: {
  filename: 'bundle.[hash:8].js',   // hash: 8只显示8位
  path: path.resolve(__dirname, 'dist'),
  publicPath: 'http://www.mayufo.cn'  // 给静态资源统一加
},

 

4.打包多页应用

// 多入口
let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  mode: 'development',
  entry: {
    home: './src/index.js',
    other: './src/other.js'
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, 'dist2')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html',
      filename: 'home.html',
      chunks: ['home']
    }),
    new HtmlWebpackPlugin({
      template: './index.html',
      filename: 'other.html',
      chunks: ['other', 'home']   // other.html 里面有 other.js & home.js
    }),
  ]
}

 

十二 配置source-map

module.exports = {
  devtool: 'source-map' // 增加映射文件调试源代码
}

 

1.源码映射 会标识错误的代码 打包后生成独立的文件 大而全 「source-map」

2.不会陈胜单独的文件 但是可以显示行和列 「eval-source-map」

3.不会产生列有行,产生单独的映射文件 「cheap-module-source-map」

4.不会产生文件 集成在打包后的文件中 不会产生列有行 「cheap-module-eval-source-map」

十三 watch 改完代表重新打包实体

module.exports = {
  watch: true,
  watchOptions: {
    poll: 1000,              // 每秒监听1000次
    aggregateTimeout: 300,   // 防抖,当第一个文件更改,会在重新构建前增加延迟
    ignored: /node_modules/  // 对于某些系统,监听大量文件系统会导致大量的 CPU 或内存占用。这个选项可以排除一些巨大的文件夹,
  },
}

 

十四 webpack的其他三个小插件

1.clean-webpack-plugin

每次打包之前删掉dist目录 yarn add clean-webpack-plugin -D
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  output: {
    path: path.resolve(process.cwd(), 'dist'),
  },
  plugins: [
    new CleanWebpackPlugin('./dist')
  ]
}

 

2.copyWebpackPlugin

一些静态资源也希望拷贝的dist中

yarn add copy-webpack-plugin -D

 

const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
  plugins: [
    new CopyWebpackPlugin([
      {from: 'doc', to: './'}
    ])
  ]
}

 

3.bannerPlugin内置模块

版权声明

 

const webpack = require('webpack');

new webpack.BannerPlugin('hello world')
// or
new webpack.BannerPlugin({ banner: 'hello world'})

 

十五 webpack解析resolve

bootstrap为例

npm install bootstrap  -D
index.js

import 'bootstrap/dist/css/bootstrap.css'

 

报错

ERROR in ./node_modules/bootstrap/dist/css/bootstrap.css 7:0
Module parse failed: Unexpected token (7:0)
You may need an appropriate loader to handle this file type.
|  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|  */
> :root {
|   --blue: #007bff;
|   --indigo: #6610f2;
 @ ./src/index.js 22:0-42
 @ multi (webpack)-dev-server/client?http://localhost:8081 ./src/index.js

 

这是因为bootstrap 4.0的css引入了新的特性,CSS Variables

安装 npm install postcss-custom-properties --save-dev

配置webpack.config.js

{
  test: /\.css$/,
  use: ['style-loader', 'css-loader', {
    loader: 'postcss-loader',
    options: {
      plugins: (loader) => [
        require("postcss-custom-properties")
      ]
    }
  }]
}

 

但是每次引入都很长,如何优雅引入

resolve: {
  // 在当前目录查找
  modules: [path.resolve('node_modules')],
  alias: {
      'bootstrapCss': 'bootstrap/dist/css/bootstrap.css'
  }
},

 

import 'bootstrapCss'  // 在node_modules查找

 

省略扩展名

resolve: {
  // 在当前目录查找
  modules: [path.resolve('node_modules')],
  // alias: {
  //   'bootstrapCss': 'bootstrap/dist/css/bootstrap.css'
  // },
  mainFields: ['style', 'main'],   // 先用bootstrap中在package中的style,没有在用main
  // mainFiles: []  // 入口文件的名字 默认index
  extensions: ['.js', '.css', '.json']  // 当没有拓展命的时候,先默认js、次之css、再次之json
},

 

定义环境变量

DefinePlugin 允许创建一个在编译时可以配置的全局常量。这可能会对开发模式和生产模式的构建允许不同的行为非常有用。

let url = ''
if (DEV === 'dev') {
  // 开发环境
  url = 'http://localhost:3000'
} else {
  // 生成环境
  url = 'http://www.mayufo.cn'
}

 

webpack.config.js

new webpack.DefinePlugin({
  // DEV: '"production"',
  DEV: JSON.stringify('production'),
  FLAG: 'true',   // 布尔
  EXPRESSION: '1 + 1'   // 字符串 如果希望是字符串 JSON.stringify('1 + 1')
})

 

区分两个不同的环境

 

分别配置不同的环境

webpack.base4.js 基础配置

webpack.dev4.js 开发环境

webpack.prod4.js 生产环境

yarn add webpack-merge -D

npm run build -- -- config webpack.dev4.js npm run build -- -- config webpack.build.js

官方文档

webpack.base4.js

 

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin')
let CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = {
  entry: {
    home: './src/index.js'
  },
  output: {
    filename: "[name].js",
    path: path.resolve(process.cwd(), 'dist3')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env'
            ]
          }
        }
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', {
          loader: 'postcss-loader',
          options: {
            plugins: (loader) => [
              require("postcss-custom-properties")
            ]
          }
        }]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      filename: 'index.html'
    })
  ]
}

 

webpack.dev4.js

 

let merge = require('webpack-merge')
let base = require('./webpack.base4.js')

module.exports = merge(base, {
  mode: 'development',
  devServer: {},
  devtool: 'source-map'
})
webpack.prod4.js
let merge = require('webpack-merge')
let base = require('./webpack.base4.js')

module.exports = merge(base, {
  mode: 'production'
})
package.json
"scripts": {
  "build": "webpack  --config webpack.prod4.js",
  "dev": "webpack-dev-server --config webpack.dev4.js"
},

 

十六 多线程打包happypack

yarn add happypack

 

let Happypack = require('happypack')


rules: [
  {
    test: /\.js$/,
    exclude: '/node_modules/',
    include: path.resolve('src'),
    use: 'happypack/loader?id=js'
  },
]

plugins: [
  new Happypack({
    id: 'js',
    use: [{
      loader: 'babel-loader',
      options: {
        presets: [
          '@babel/preset-env',
          '@babel/preset-react'
        ]
      }
    }]
  })
]

 

js启用多线程,由于启用多线程也会浪费时间,因此当项目比较大的时候启用效果更好

css启用多线程

{
  test: /\.css$/,
  use: 'happypack/loader?id=css'
}

new Happypack({
  id: 'css',
  use: ['style-loader', 'css-loader']
}),

 

十七 抽取公共代码

1.抽离自有模块

module.exports = {
  optimization: {
    splitChunks: {             // 分割代码块,针对多入口
      cacheGroups: {           // 缓存组
        common: {              // 公共模块
          minSize: 0,          // 大于多少抽离
          minChunks: 2,        // 使用多少次以上抽离抽离
          chunks: 'initial'    // 从什么地方开始, 从入口开始
        }
      }
    }
  },
}

SplitChunksPlugin

2.抽离第三方模块

optimization: {
  splitChunks: {              // 分割代码块,针对多入口
    cacheGroups: {            // 缓存组
      common: {               // 公共模块
        minSize: 0,           // 大于多少抽离
        minChunks: 2,         // 使用多少次以上抽离抽离
        chunks: 'initial'     // 从什么地方开始,刚开始
      },
      vendor: {
        priority: 1,          // 增加权重, (先抽离第三方)
        test: /node_modules/, // 把此目录下的抽离
        minSize: 0,           // 大于多少抽离
        minChunks: 2,         // 使用多少次以上抽离抽离
        chunks: 'initial'     // 从什么地方开始,刚开始
      }
    }
  },
},

 

十八 懒加载(延迟加载)

yarn add @babel/plugin-syntax-dynamic-import -D

 

source.js

 

export default 'mayufo'

 

index.js

 

let button = document.createElement('button')
button.innerHTML = 'hello'
button.addEventListener('click', function () {
  console.log('click')
  // es6草案中的语法,jsonp实现动态加载文件
  import('./source.js').then(data => {
    console.log(data.default)
  })
})
document.body.appendChild(button)

 

{
  test: /\.js$/,
  exclude: '/node_modules/',
  include: path.resolve('src'),
  use: [{
    loader: 'babel-loader',
    options: {
      presets: [
        '@babel/preset-env',
        '@babel/preset-react'
      ],
      plugins: [
        '@babel/plugin-syntax-dynamic-import'
      ]
    }
  }]
}

 

十九 热更新(当页面改变只更新改变的部分,不重新打包)

plugins: [
  new HtmlWebpackPlugin({
    template: './src/index.html',
    filename: 'index.html'
  }),
  new webpack.NameModulesPlugin(),          // 打印更新的模块路径
  new webpack.HotModuleReplacementPlugin()  // 热更新插件
]

 

index.js

 

import str from './source'

console.log(str);

if (module.hot) {
  module.hot.accept('./source', () => {
    console.log('文件更新了');
    require('./source')
    console.log(str);
  })
}

 

标签:use,webpack4,module,js,学习,webpack,loader,css
来源: https://www.cnblogs.com/feifan1/p/12636942.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有