webpack

webpack 4x

中文文档:https://www.webpackjs.com/concepts/

网页中的静态资源

  • js : .js .jsx(react).coffee .ts(Typescript 类 c#语言)
  • css: css .less .sass(基本没用了) .scss
  • Images
  • 字体模板
  • 模板文件 : .ejs .jsde .vue

静态资源多了有什么问题?

  1. 网页加载速度慢, 因为 我们要发起很多的二次请求;
  2. 要处理错综复杂的依赖关系

如何解决上述两个问题

  1. 合并、压缩、精灵图、图片的Base64编码
  2. 可以使用webpack可以解决各个包之间的复杂依赖关系;

压缩合并工具:

  • gulp是基于task任务的 (小乔,灵活,便于小项目的构建)
  • webpack 基于整个项目构造()

简介

webpack是前端的一个项目构建工具,它基于Node.js开发出来的一个前端工具

注意

es6语法浏览器无法识别,得降低版本

能做什么?

  1. 能处理js文件的互相依赖关系
  2. 能处理js的兼容问题,把高级的、浏览器不识别的语法,转为低级的,浏览器能正常识别的语法

安装webpack

先全局安装

  1. 安装:npm install -g webpack
  2. 安装脚手架:npm install -g webpack-cli
  3. 也可以一次安装两个:yarn add webpack webpack-cli
  4. 检查版本号(没有版本号代表安装失败):webpack -v

再局部安装

  1. 安装:npm install webpack -D
  2. 安装脚手架:npm install webpack-cli -D
  3. 也可以一次安装两个:yarn add webpack webpack-cli -D (-D就是--save-dev 。-S就是--save)

动手:

最简单的打包,使用默认0配置,啥都不配置。

  • 新建一个项目文件,yarn init -y,初始化默认包配置文件
  • 局部安装webpackyarn add webpack webpack-cli -D
  • 新建src文件夹,里边新建一个index.js,随便编写脚本文件
  • npx webpack,发现会有一个dist目录生成,里边有一个压缩过的main.js
  • 在src和dist中分别创建一个index.html引入各自的js。分别在浏览器中打开。

知识点:

  • npx是npm v5.2引入的一个命令,npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你安装!

  • 压缩过的js会多出很多代码,为什么?

    • 打包,默认支持js的模块化,多出来的很多东西是关于模块化的兼容
  • dist中html在浏览器中能正常输出,src中的html却会报错‘require is not defined’,为什么?

    • dist中的打包出来的代码,模块化相关的东西是经过兼容处理的,所以不会报这个错
    • src里边的代码没有引入模块化相关的js文件,所以会报错。
    • 但是在命令行中用node执行是不会报错的,因为node环境中有模块化相关的js文件

手动配置webpack

默认webpack的配置文件时webpack.config.js。名字是死的,

webpack-cli/bin/config-yargs.js中搜索webpack.config.js,默认有两个名字可以用

出口入口和模式

 
 
 
 
 
 
 
 
let path = require('path');//模块用于处理文件与目录的路径
module.exports = {
    mode:'development',//打包模式:开发或生产
    entry:'./src/01.js',//目标文件
    output:{
        filename:'bundle.js',//输出的名字
        path:path.resolve(__dirname,'build')//必须是绝对路径:
        //publicPath:'https://static2.yscase.com/'//把所有路径都加上cdn前缀地址
        //node的path对象的resolve方法可以把当前路径转为绝对路径
        //__dirname:当前模块的目录名
        //参考说明:http://nodejs.cn/api/path.html#path_path_resolve_paths
    }
}
 

自定义的配置文件名字

如:webpack.config.my.js

执行时,要这样执行:webpack --config webpack.config.js

配置package.json脚本

如果嫌弃命令语句太长,可以在package.json里添加脚本语句

 
 
 
xxxxxxxxxx
 
 
 
 
"scripts":{
    "build":"webpack --config webpack.config.my.js"
 },
 

执行yarn run build

webpack-dev-server

启动一个服务器,在服务器上预览

  • 安装yarn add webpack-dev-server -D

  • 配置

     
     
     
    xxxxxxxxxx
     
     
     
     
    devServer:{
        progress:true,
        contentBase:'./build',//指定文件夹
        port:3000,//设置端口号
        compress:true,//压缩
    },
     
  • 添加到脚本

     
     
     
    xxxxxxxxxx
     
     
     
     
    "scripts": {
       "dev": "webpack-dev-server"
    }
     
  • 执行yarn run dev

html打包

html-webpack-plugin(插件)

会自动引入js

普通单页面

  • 安装插件yarn add html-webpack-plugin -D

  • 配置package,添加脚本

     
     
     
    xxxxxxxxxx
     
     
     
     
    "scripts": {
        "build": "webpack",
    },
     
  • 配置插件(你的第一个插件)

    • 先在顶部引入

       
       
       
      xxxxxxxxxx
       
       
       
       
      let HtmlWebpackPlugin = require('html-webpack-plugin');//打包html
       
    •  
       
       
      xxxxxxxxxx
       
       
       
       
      plugins:[
          new HtmlWebpackPlugin({
              template:'./src/index.html',//要打包的html
              filename:'index.html',//输出的文件名
              minify:{
                  removeAttributeQuotes:true,//删除双引号
                  collapseWhitespace:true,//删除换行和空格
              },
              hash:true//hash随机数,给引用文件添加版本号
          })
      ]
       
  • 压缩html

     
     
     
    xxxxxxxxxx
     
     
     
     
    new HtmlWebpackPlugin({
       minify:{
           removeAttributeQuotes:true,//删除双引号
           collapseWhitespace:true,//删除换行和空格
       },
    })
     
  • hash戳解决缓存问题

    • 给引用文件添加版本号

       
       
       
      xxxxxxxxxx
       
       
       
       
      new HtmlWebpackPlugin({  
         hash:true//hash随机数,给引用文件添加版本号
      })
       
    • 文件名添加hash

       
       
       
      xxxxxxxxxx
       
       
       
       
      output:{
         filename:'bundle.[hash:8].js',//输出的名字
      },
      //加:8代表只显示8位hash值
       
  • 执行yarn run build

多页应用打包

有各自的html和入口js文件

 
 
 
xxxxxxxxxx
 
 
 
 
const Path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    mode:'development',
    entry:{ //多页时,写成对象模式,起个名字
        home:'./src/index.js',
        share:'./src/share.js'
    },
    output:{
        filename:'[name].js', //此时name为入口时起的名字
        path:Path.resolve(__dirname,'dist')
    },
    plugins:[
    //HtmlWebpackPlugin插件有几个页面就实例化几个
        new HtmlWebpackPlugin({
            template:'./src/index.html',
            filename:'index.html',
            chunks:['home']//指定入口文件
        }),
        new HtmlWebpackPlugin({
            template:'./src/share.html',
            filename:'share.html',
            chunks:['share']//指定入口文件
        })
    ]
}
 

样式打包

打包css,less

打包css,less(less-loader),sass等

  • 安装依赖yarn add css-loader style-loader -D

  • webpack‘配置文件,

     
     
     
    xxxxxxxxxx
     
     
     
     
    module:{
        rules: [
            {
                test: /.css$/,
                use: [
                { loader: "style-loader" },//写成对象时可以配置参数
                "css-loader" ,//直接写字符串不能配置参数
                ],
            }
        ],
    }
     
  • css-loader:解决@import

  • style-loader:把css内容嵌入html

  • 注意,use数组元素执行顺序是后往前,先css-loader,再style-loader

  • 如是less

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

分离css

  • 安装mini-css-extract-plugin插件yarn add mini-css-extract-plugin -D

  • 是插件,就要在顶部引入

     
     
     
    xxxxxxxxxx
     
     
     
     
    let MiniCssExtractPlugin = require('mini-css-extract-plugin');//分离css
     
  • 配置插件参数

     
     
     
    xxxxxxxxxx
     
     
     
     
    new MiniCssExtractPlugin({
       //filename:'main.css',//输出的文件名
       filename:'css/main.css',//输出到指定文件夹
    })
     
  • 把原来的style-loader替换成MiniCssExtractPlugin.loader,原来的style-loader用于把css嵌入html,现在不需要了,而是,MiniCssExtractPlugin会生成一个link标签且分理处一个css文件,在html中引用

     
     
     
    xxxxxxxxxx
     
     
     
     
    {
        test: /.css$/,
        use: [
            MiniCssExtractPlugin.loader,
            "css-loader",
        ]
    },
     
  • 如是less文件的页同理

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

给css,less添加前缀

postcss-loader 用来处理css优化的 autoprefixer是其中一种优化:添加浏览器前缀

  • 安装yarn add postcss-loader autoprefixer -D

  • css-loader之前执行

     
     
     
    xxxxxxxxxx
     
     
     
     
    {
        test: /.css$/,
        use: [
            MiniCssExtractPlugin.loader,
            "css-loader",
            "postcss-loader",//一定放在css-loader后面,才会先执行
        ],
    },
     
  • 如是less

     
     
     
    xxxxxxxxxx
     
     
     
     
    use: [
        MiniCssExtractPlugin.loader,
        "css-loader" ,
        "postcss-loader",//less-loader之后执行,css-loader之前执行
        "less-loader" ,
    ],
     
  • 添加postcss配置文件postcss.config.js

  •  
     
     
    xxxxxxxxxx
     
     
     
     
    module.exports = {
        plugins:[
          require('autoprefixer')
        ]
    }
     
  • 注意:请尽量在js中引入css或less,如果在css或less中引入css或less,@import导入的内容不会被自动添加浏览器前缀!

压缩css

把mode设置为production,webpack打包一下,会发现js会自动压缩,但css不会

  • 安装所需要的模块

  • 把mode设置为production生产模式

  • 配置文件顶部引入模块 yarn add optimize-css-assets-webpack-plugin UglifyJsPlugin -D

     
     
     
    xxxxxxxxxx
     
     
     
     
    //压缩css
    const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
    //用于压缩js,如果要压缩css就必须添加压缩js的,否则js将不会压缩,
    const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
     
  • 配置参数

     
     
     
    xxxxxxxxxx
     
     
     
     
    optimization: {
        minimizer: [
        //压缩js
            new UglifyJsPlugin({
                cache: true,//缓存
                parallel: true,//是否并发打包
                sourceMap: true // 高级js 转es5会用到 source maps
            }),
            //压缩css
            new OptimizeCSSAssetsPlugin({})
        ]
    },
     
  • 执行yarn run build查看build文件夹中js和css是否都是压缩的

图片资源打包

file-loader

官网https://webpack.js.org/loaders/file-loader/

html-withimg-loader

js中引用的图片,css中的背景图片,html中的img标签图片,

file-loader匹配出找所有的图片,创建一个新的图片到指定目录,默认会生成新的带hash值的名字

  • 安装本地依赖yarn add file-loader -D

  • 配置loader

     
     
     
    xxxxxxxxxx
     
     
     
     
    {
        test: /.(png|jpg|gif)$/,
        use: 'file-loader'
    },
     
  • 读取图片

    • js中的图片

      • 需要通过引入(import或require),才会被打包成新的图片

         
         
         
        xxxxxxxxxx
         
         
         
         
        import girl from './girl.jpg';//引入图片
        console.log(girl);//新的图片路径
        let img = new Image();
        img.src = girl;
        document.body.appendChild(img);
         
    • css中的背景图片

      • 使用了css-loader的话,css中的背景图片都能显示正常,因为css的路径都会被转为url(require("./logo.png")),这样就会主动去生成新的路径并直接返回了
    • html中的图片

      • 默认html中的图片不会被打包,因为没有被依赖,没有通过引入(import或require)

      • 我们需要安装一个新的loader,用来解决这个问题yarn add html-withimg-loader -D

      • 在loader中添加规则

         
         
         
        xxxxxxxxxx
         
         
         
         
        {
            test: /.html$/,
            use: 'html-withimg-loader'
        },
         
  • 打包执行yarn run build

输出到指定文件夹

 
 
 
xxxxxxxxxx
 
 
 
 
{
    test: /.(png|jpg|gif)$/,
    use: {
        loader:'file-loader',
        options:{
            limit:1,//小于最小体积就转为base64
            outputPath:'img/',//指定文件夹
            name:'[name]-[hash:6].[ext]',//名字
            //publicPath:'https://static2.yscase.com/'//把所有图片都加上cdn前缀地址
        }
    }
}
 

高级js转es5

babel官网:https://babeljs.io/docs/en/

配合官网文档,更细致,在打包报错时,会有报错提示,看提示是缺少什么插件(包/模块),我们就去官网上搜索,查看使用

基本的es6

@babel/core是babel-loader的核心,

@babel/preset-env处理转化

声明语句,箭头函数,class类

babel-loader

@babel/core

@babel/preset-env

  • 安装yarn add babel-loader @babel/core @babel/preset-env -D

  • 添加规则

     
     
     
    xxxxxxxxxx
     
     
     
     
    {
        test: /.js$/,
        exclude: /(node_modules|bower_components)/,//匹配时排除该文件夹
        use: {
            loader: 'babel-loader',
            options: {
                presets: ['@babel/preset-env'] //预设
            }
        }
    }
     

class类静态属性

plugin-proposal-class-properties

https://babeljs.io/docs/en/next/babel-plugin-proposal-class-properties.html

  • 安装针对class类的转化 yarn add @babel/plugin-proposal-class-properties -D

  • 添加插件配置

     
     
     
    xxxxxxxxxx
     
     
     
     
        use: {
            loader: 'babel-loader',
            options: {
                presets: [
                    '@babel/preset-env'
                ],
                plugins:[
                    '@babel/plugin-proposal-class-properties' //针对class
                ]
            }
    }
     
  • 执行yarn run build

装饰器

plugin-proposal-decorators

  • 安装依赖yarn add @babel/plugin-proposal-decorators -D

  • 用法:https://babeljs.io/docs/en/babel-plugin-proposal-decorators注意babel插件plugins顺序

     
     
     
    xxxxxxxxxx
     
     
     
     
    options: {
        presets: [
            '@babel/preset-env'
        ],
        plugins:[
            ["@babel/plugin-proposal-decorators", { "legacy": true }],//宽松模式
            ["@babel/plugin-proposal-class-properties", { "loose" : true }]
        ]
    }
     

transform-runtime

如果你用了generator函数,打包时没有报错,但是打包后的代码在浏览器中却是报了错regeneratorRuntime is not defined

此时你还需要安装@babel/plugin-transform-runtime,帮助转化的包

plugin-transform-runtime还可以优化代码,减少重复的代码

  • 安装开发时的依赖yarn add @babel/plugin-transform-runtime -D

  • 安装生产上线时的依赖yarn add @babel/runtime -S

  • 添加到babel依赖插件中

     
     
     
    xxxxxxxxxx
     
     
     
     
    plugins:[
        ["@babel/plugin-proposal-decorators", { "legacy": true }],//宽松模式
        ["@babel/plugin-proposal-class-properties", { "loose" : true }],
        "@babel/plugin-transform-runtime"
    ]
     
  • 执行打包yarn run build

更高级的语法

This means you can use new built-ins like Promise or WeakMap, static methods like Array.from or Object.assign, instance methods like Array.prototype.includes, and generator functions (provided you use the regenerator plugin).

源自babel官网: https://babeljs.io/docs/en/babel-polyfill#docsNav

@babel/polyfill

  • 安装生产上线时的依赖yarn add @babel/polyfill -S

  • js入口顶部引入

    • require("@babel/polyfill");
    • import "@babel/polyfill";
  • 执行打包,打包后的页面在ie中也能正常执行,没有使用这款插件的在低版本浏览器会报错的

ESLint高级js语法检验

官网:https://eslint.org/

暴露全局变量

require引入的是在当前模块,并不是全局,如要暴露给全局,如下

expose-loader

expose-loader暴露给全局(目前juqery已经是全局的了,再次只是比如)

  • 安装expose-loader yarn add expose-loader -D

  • 使用

    • 引入时设置变量import $ from 'expose-loader?$!jquery'

    • webpack配置添加匹配规则

      {
          test:require.resolve('jquery'),
          //详解见http://nodejs.cn/api/modules.html#modules_require
          use:[{
              loader:'expose-loader',
              options:'$'//暴露出来的全局变量
          }]
      },
      
  • 打包运行

ProvidePlugin

ProvidePlugin在每个js模块中引入插件

  • 先引入const Webpack = require('webpack')

  • 再配置插件

    new Webpack.ProvidePlugin({
        $:'jquery',
        jquery:'juqery'
    })
    
  • 打包运行

webpack常用配置

sourcemap源码映射

打包后的代码都被压缩了,浏览器上不好找到报错的地方,我们可以通过sourcemap找到报错的地方行和列

官网文档:https://webpack.js.org/configuration/devtool/#devtool

module.exports = {
    mode:'production',
    //源码映射,会单独生成一个sourcemap文件,浏览器调试时出错会标识列和行
    devtool:'source-map',
    //源码映射,不会产生单独的文件,但是浏览器调试时可以显示行和列
    devtool:'eval-source-map',
    // 不会产生列,但是是一个单独的映射文件
    devtool:'cheap-module-source-map',
}

watch

实时打包更新


常用插件

cleanWebpackPlugin

打包前清空文件夹https://www.npmjs.com/package/clean-webpack-plugin

  • 先安装yarn add clean-webpack-plugin -D

  • 引入插件

    const CleanWebpackPlugin = require('clean-webpack-plugin');
    
  • plugins:[
        new CleanWebpackPlugin('./dist')//传入要清空的文件夹,也可以是数组
    ],
    

copyWebpackPlugin

复制文件到指定目录

  • 先安装yarn add copy-webpack-plugin -D

  • 引入插件

    const CopyWebpackPlugin = require('copy-webpack-plugin');
    
  • plugins:[
        new CopyWebpackPlugin([
            {from:'./other',to:'./other'}//从根目录到输出目录
        ])
    ],
    

bannerPlugin 内置

给打包后的文件顶部嵌入标识语句,

  • webpack内置插件,引入webpack即可

    const Webpack = require('webpack');
    
  • new Webpack.BannerPlugin({
       banner:'2019.2.13by xiaoyue'//指定内嵌语句
    })
    

跨域问题

奔跑的蜗牛
原文地址:https://www.cnblogs.com/xiaoyue-/p/10608761.html