webpack基本学习

178 阅读5分钟

webpack介绍

为什么要打包呢,因为你用react,vue写的浏览器不认识,ES6也不能被完全兼容,所以打包转成浏览器认识的代码。那打包完的代码还算MVVM嘛,那必须的。没有优化的打包,bundle文件就像是一桶水,优化后,桶装水就被分成了大小不一的瓶装压缩~~'农夫三拳'~~。


前后端分离,代码模块化,组件化开发的单页面应用。最后还是要打包成HTML加载js,css,图片等资源的形式 - 涉及到打包,SEO问题

单页面应用所有的都在一个页面完成 - 涉及到路由问题

webpack大概就是:找到入口文件,然后递归依赖模块,收集依赖,然后开始转换,比如通过babel将ES6转为AST(抽象语法树)再转为ES5。通过less-loder将less转为css。最后用eval运行生成bundle文件

"webpack": "^4.35.2",

webpack.config.js -> github.com/coldLemon/w…

run build结果如下,该图片为speed-mesure插件运行结果 image.png

下图为打包后的文件结构

image.png

打包完也就是我们所熟悉的HTML+CSS+JS基本形式 下面来介绍一下:webpack几个基本模块

  • entry(入口)

`` 可以是单个入口:字符串 也可以是多个入口:数组,对象(官方推荐) 多个入口主要用来打包区分第三方库与业务代码(webpack4+已不推荐),也可以打包成多页面。

entry: {
  main: "./src/index.js",  
  //main也是打包输出后的文件名
},
  • output(打包输出)
  output: {
    path: path.join(__dirname, '/dist'), 
    //1.path:入磁盘路径  2.__dirname:当前文件同级目录
    filename: "[name].[hash:8].js"
    //[name]:占位符,本文与entry的main 对应
    //[hash:8] 模块层面的hash,8代表8位
  },
  • Module
{
        test: /\.(css|less|sass)$/, 
        //正则匹配 ‘.’是以啥开头,$是以啥结尾 |就是或
        use: [ //使用啥loader来解析匹配到的文件
          MiniCssExtractPlugin.loader,
          // 'style-loader',  //官网tip: 该插件不能和style 一起用
          'cache-loader',    //loader缓存
          'css-loader', 
          'less-loader'
        ],
        // exclude: /node_modules/   
        //这里不明白node_modeles的less 也需要loader 来处理?

通过test正则匹配文件的后名,然后用相对用的loader处理

  • Resolve
  resolve:{
    extensions:['.js','.vue','.json'],
    //文件若无结尾,会按数组顺序逐个为文件匹配。(文件可以不加扩展名)
    alias:{//文件路径简写
      Components : path.resolve(__dirname,'src/components/'),
      Pages: path.resolve(__dirname,'src/pages/')
    }
  }
}
  • Plugins

plugin就是个构造函数吧。具体用法还是要见构造函数干啥用的

plugins: [
    new HtmlWebpackPlugin({
      title: 'gege',
      template: path.resolve(__dirname,'index.html'),///指定要打包的html路径和文件名
      filename: "index.html",//指定输出路径和文件名(相对js的路径)
      hash: true,
      minify: {
        //压缩HTML
        removeComments: true,
        collapseWhitespace: true
      }
    })
    ,
    new MiniCssExtractPlugin({
      // filename:'[name]_[contenthash:8].css'
      filename:'[name].css',
      chunkFilename:'[id].css',
    }),
    new VueLoaderPlugin(),
    new CleanWebpackPlugin(),
  ],
  

再优化

其实上面也边做优化了,下面再进一步的

  • 按需加载
module.exports = {
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",  //安装babel-plugin-component 饿了吗->vue用
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
    // [
    //   "import",{  //安装babel-plugin-import ant->antd用
    //     "libraryName":"element-ui",
    //   }
    // ]
  ]
}
  • optimization(优化)
splitChunks: {  //分割第三方库
      chunks: "all",          //async异步代码分割 initial同步代码分割 all同步异步分割都开启
      minSize: 30000,         //字节 引入的文件大于30kb才进行分割
      //maxSize: 50000,         //50kb,尝试将大于50kb的文件拆分成n个50kb的文件
      minChunks: 1,           //模块至少使用次数
      maxAsyncRequests: 5,    //同时加载的模块数量最多是5个,只分割出同时引入的前5个文件
      maxInitialRequests: 3,  //首页加载的时候引入的文件最多3个
      automaticNameDelimiter: '~', //缓存组和生成文件名称之间的连接符
      name: true,                  //缓存组里面的filename生效,覆盖默认命名
      cacheGroups: { //缓存组,将所有加载模块放在缓存里面一起分割打包
        vendors: {  //自定义打包模块
          test: /[\\/]node_modules[\\/]/,
          priority: -10, //优先级,先打包到哪个组里面,值越大,优先级越高
          filename: 'vendors.js',
        },
        default: { //默认打包模块
          priority: -20,
          reuseExistingChunk: true, //模块嵌套引入时,判断是否复用已经被打包的模块
          filename: 'common.js'
        }
      }
    }
  • DLLPlugin(单独打包)

大概就是将不怎么更新的包单独用webpack 打包(单独配置一个webpack.vender.config js文件),然后会生成manifest,相当于包依赖图。然后在html引入js 打包出的js 即可。这个和optmization.splitchunks单独打包成一个js类似吧。还有用externals引入第三方库,用CDN加载也一样吧。

const path=require('path')
const webpack =require('webpack')
const {CleanWebpackPlugin}  = require('clean-webpack-plugin');


const dllBasePath = path.join(__dirname, 'dist','dll');
//只需要使用yarn dll一次就行
module.exports={
    // mode:'production',
    mode:'development',
    entry:{
    	//把
        vue:['vue','vue-router','vue-axios','vuex']
    },
    output:{
        filename:'[name]_[hash].js',
        //产出名字,(js引入的文件名,这里在HTML-webpack-plugin 对应)
        path:dllBasePath, //js输出路径
        library:'[name]_[fullhash]',  //类库引入方式,import require and so on
        libraryTarget: 'umd'
    },
    plugins:[
        new webpack.DllPlugin({ //将此插件与output.library选项结合使用以公开(也称为全局作用域)dll函数
          // context: __dirname,
            
          //name:'[name]_[fullhash]',
           manifest: require(path.resolve(__dirname, 'dist', 'manifest.json')),
            //清单json文件的绝对路径(输出)
            // entryOnly: true //仅公开入口点
        }),
        new CleanWebpackPlugin({ //这里要对象,数组会报错
          // cleanOnceBeforeBuildPatterns: [path.resolve(__dirname,'dist/dll')]
        }),//删除dll目录下的文件
    ]
}

yarn dll 后产不出manifest文件(路径问题),后来去react-cli看了下,它们的manifest都是在最外层的,还是两个,一个文件映射,一个是图片。然后我就改了manifest的输出路径到dist根目录下。 path:require(path.join(__dirname,'dist','manifest.json')),


现在打包后如下图所示: image.png image.png

打包速度是快了,但是打开dist文件中的css,发现未被压缩swiper等一些第三方组件也还没被压缩,被复用两次以上的element-ui还很大。

还有yarn start 后样式置空没了。低级错误:查询后是我将blank.css置空样式直接在index.html中导入,导致webpack从index.js入口中不能递归到css,在index.js中引入css即可

  • 压缩css

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')//压缩css

引入后,在插件配置中new一个就完了。然后build之后可以看到css被压缩了

image.png

总结

基本打包后,需要优化。大概需要提取第三方组件库
  • 1.用externals,然后cdn引入
  • 2.optimization.splitchunks分割代码
  • 3.webpack.dllplugin单独打包

webpack独有的require.ensure(打包后会单独形成代码块,通过jsonp按需加载)实现路由懒加载。多线程打包,压缩js

本人小学毕业,所以这里只是基本配置,也参考(CV)了很多文章,学习用,如有错误请严格指出,本人临码涕零,thanks q U

~~现在学的好,五年后炒河粉没烦恼~~