webpack学习笔记(二)

1 支持es6语法 

(注意直接写map等es6语法,由于现代浏览器是支持的,所以可以显示出来,可以执行 npm run build 命令,在生成的文件中,查看map等es6语法是没有被转成es5的)

1.1 首先安装 babel-loader和babel的核心库: npm install -D bable-loader @babel/core 

module.exports = {
    module: {
        rules: [{ 
            test: /\.js$/, 
            exclude: /node_modules/,  //排除这个文件夹下的内容 
            loader: 'babel-loader',
        }]
    }
}

1.2 安装    npm install @babel/preset-env -D   需要在特定的平台上执行特定的转码规则,preset-env 说白了就像是按需转码的意思

module.exports = {
    module: {
        rules: [{ 
            test: /\.js$/, 
            exclude: /node_modules/, 
            loader: 'babel-loader',
            options: {
                presets: ['@babel/preset-env']  //在这里配置使用loader的配置项
            }
        }]
    }
}

1.3 此时诸如 let等已经转成H5 了,还有一些es6语法不能转过去,比如箭头函数,使用polyfill

 npm install --save @babel/polyfill

1.4 在业务代码中引入: 

import "@babel/polyfill"

由于会把所有的转换方法打包,所以会导致js文件变的非常大,而我们只用了几个es6的语法

module.exports = {
    module: {
        rules: [{ 
            test: /\.js$/, 
            exclude: /node_modules/, 
            loader: 'babel-loader',
            options: {
                presets: [['@babel/preset-env',{ //这里要给preset-env设置参数 所以要放在数组中
                    useBuiltIns:'usage' //根据业务代码使用的es6语法 来添加对应的转换方法
                }]]  
            }
        }]
    }
}

还可以配置转换的环境,进一步优化缩小打包代码:

//针对各个浏览器的最新的两个版本,以及safari的版本7及以上,针对以上两个条件的兼容情况进行代码转译
{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"] 
      }
    }]
  ]
}

 1.5 由于babel的可配置项特别多,所以可以将其提取出来放在 .babelrc 文件中,然后把options的对象整个放在这个文件中

 注意:

1:

Babel 7 的相关依赖包需要加上 @babel scope。一个主要变化是 presets 设置由原来的 env 换成了 @babel/preset-env, 可以配置 targetsuseBuiltIns 等选项用于编译出兼容目标环境的代码。其中useBuiltIns如果设为 "usage",Babel 会根据实际代码中使用的ES6/ES7代码,以及与你指定的targets,按需引入对应的 polyfill,而无需在代码中直接引入 import '@babel/polyfill'避免输出的包过大,同时又可以放心使用各种新语法特性。

{
  "presets": [
    ["@babel/preset-env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      },
      "useBuiltIns": "usage"
    }]
  ]
}

配置文件中:

{
      test:/\.js$/,
      exclude: __dirname + 'node_modules',
      use: 'babel-loader'  //注意这里要用的是 use 不要直接使用 loadder 否则转化es5 不生效!!!!!!!
}

2:    webpack4.x下babel的安装、配置及使用

3: 配置打包时报Cannot read property 'bindings' of null 或 Cannot find module '@babel/core'问题

webpack学习笔记(二)_第1张图片

解决:模块中对js的处理配置如下图可解决

  webpack学习笔记(二)_第2张图片  

或者使用:

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

 

 

 

2 使用webpack 搭建react的运行环境

2.1  首先安装react  npm install react react-dom --save 

然后在 .babelrc

{
    presets:[
        [
            "@babel/preset-env",{
                targets:{
                    chrome:"67",
                },
                useBuiltIns: 'usage'
            }
        ],
        "@babel/preset-react"  //执行顺序是 从下往上 从右往左
    ]
}

注意的是:

 

如果在babel的配置中写了    useBuiltIns: 'usage'  (只使用用到了的方法) 则会自动引入 import  "@babel/polyfill"  所以不需要在业务代码中再次引入。

 

3 tree shaking 只打包引用的文件代码,例如定义 build.js:

export const add = (a,b)=>{
    console.log(a+b)
}

export const minus = (a,b)=>{
    console.log(a-b)
}

在其他文件中引入:import { add } from './build.js' 

则在生成的文件中,你会发现即使没有调用 minus方法,也会把整个的build.js 进行打包编译。为了只对使用过的方法进行打包,进行如下操作:

首先明确的是  tree shaking 只对  import { add } from './build.js'  起作用,而对  const add = require ('./build.js') 不起作用

module.exports = {
    mode: 'development',
    module: {
    },
    plugins: [
    ],
    optimization: {
        usedExports: true //在这里进行配置
    },
    output: {
    }
}

但是这样的话对于 没有 引入具体 函数的:  import '@babel/polly-fill'  会不进行打包

所以要在package.json配置文件中 添加: "sideEffects":["@babel/polly-fill"] ,即对不需要使用 tree-shaking 进行操作的文件,放在这里,

但是一般我们不需要在文件中 引入这些的话 ,需要tree-shaking 对所有import的文件进行 按需处理 ,所以这里写成false : "sideEffects":false 

但是对于没有具体引出的 css: import './index.css' ,json配置文件中需要重新定义: "sideEffects":["*.css"] 

最后 对于开发模式,虽然能够识别,但是便于开发调试,没有删掉未引用的代码,在上线的模式 中:

mode: 'development', //开发环境

mode: 'production' // 上线环境
// tree-shaking 已经把 optimization 写好了 
// 所以删除
// optimization: {
//     usedExports: true //在这里进行配置
// },

然后搜索打包后的js文件,发现没有引入的方法不再有了。

4 对webpack的配置文件进行模式区分:新建两个配置文件,其中 webpack.dev.js 的 mode是 mode: 'development' 

{
    "scripts":{
        "dev":"webpack-dev-server --config webpack.dev.js",
        "build":"webpack --config webpack.prod.js"
    }
}

4.1 由于两个文件重复性很大,所以把共有的代码放在新建的文件中: webpack.common.js;

这样就会有三个配置文件 分别是 共性的代码  webpack.common.js;开发的配置文件 webpack.dev.js;上线的文件 webpack.prod.js。

然后使用webpack-merge进行文件的合并: npm install webpack-merge -D 

const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');

const devConfig = {
    mode:'',
    devtool:'',
    devServer:{

    }
}
module.exports = merge(commonConfig,devConfig); 
//这样使用 merge 合并后导出 commonConfig 和 devConfig

 如果把这三个配置文件放在build文件夹下,则config.json中相应的修改:

 "dev":"webpack-dev-server --config ./build/webpack.dev.js" 

 

webpack学习笔记(二)_第3张图片   同样配置文件中也要修改:

{
    //CleanWebpackPlugin插件会默认当前文件为根路径,
    //所以需要用root参数,配置当前的根路径
    plugins:[
        new CleanWebpackPlugin(['dist'],{  //dist路径是在root相对下的路径
            root:path.resolve(__dirname,'../') 
        })
    ],
    output:{
        filename:'[name].js',
        path:path.resolve(__dirname,'../dist') //这做修改里也要
    }
}

 

5. code Splitting 即代码拆分  比如要提取出公共的 lodash代码

5.1 首先安装  npm install lodash --save  该库可以用来操作一些字符串,

比如:

import _ from 'lodash';
var element = document.createElement('div');
element.innerHTML = _.join(['Dell', 'Lee'], '-');
document.body.appendChild(element);

然后在配置文件中,在和entry,module等并列的位置:

optimization:{
  splitChunks:{
      chunks:'all'
  }
}

就可以自动打包出vendor.js;

5.2 异步引入的js库

function getComponent() {
    return import('lodash').then(({ default: _ }) => {
        var element = document.createElement('div');
        element.innerHTML = _.join(['Dell', 'Lee'], '-');
        return element;
    })
}

getComponent().then(element => {
    document.body.appendChild(element);
});

但是打包不支持,所以安装: npm install babel-plugin-dynamic-import-webpack //动态引入import 

因为引入了新的babel,所以要在babelrc文件中修改:

{
    presets: [
        [
            "@babel/preset-env", {
                targets: {
                    chrome: "67",
                },
                useBuiltIns: 'usage'
            }
        ],
        "@babel/preset-react"
    ],
   plugins: ["dynamic-import-webpack"] //修改了这里
}

代码分割和webpack无关,

webpack 中实现代码分割,两种方式:

1. 同步代码: 只需要在webpack.common.js 中做 optimization 的配置

2. 异步代码: 无需做任何配置需要安装上述插件;

以上promise代码还可以简化成async模式:

async function getComponent() {
  const { default:_ } = await import( /* webpackChunkName:"lodash" */ 'lodash' );
  var element = document.createElement('div');
  element.innerHTML = _.join(['Dell', 'Lee'], '-');
  return element;
}

getComponent().then(element => {
 document.body.appendChild(element);
});

5.3 以上不是官方插件,所以不要看上面的了,看下面的官方插件(在babel的官网上):

首先安装: npm install --save-dev @babel/plugin-syntax-dynamic-import 

plugins: ["@babel/plugin-syntax-dynamic-import"]

然后使用方式为:

function getComponent() {
    return import(/* webpackChunkName:"lodash" */ 'lodash').then(({ default: _ }) => {
        var element = document.createElement('div');
        element.innerHTML = _.join(['Dell', 'Lee'], '-');
        return element;
    })
}

getComponent().then(element => {
    document.body.appendChild(element);
});

config文件中:

optimization: {
        splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendors:false ,
        default:false
      }
    }
}

更多配置:

optimization: {
  splitChunks: {
    chunks: 'all',//同步异步全都打包
    minSize: 30000,//打包的库或者文件必须大于这个字节才会进行拆分
    minChunks: 1,//规定当模块在生成的js文件(trunk)中被调用过多少次的时候再进行拆分
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    automaticNameDelimiter: '~',//如果不写filename 默认名字 组名~[name]
    name: true,
    cacheGroups: {//缓存组,因为需要打包完成之后,在把所有要拆分的代码合并拆分,所以先要缓存
      vendors: {
        test: /[\\/]node_modules[\\/]/, //如果上面chunks定为all,就是找到所有的import文件,看他是不是调用于 node_modules 文件夹 是的话就拆分
        priority: -10,//优先级 比如同时符合vender 和 default 这个优先级高 所以存在这里
        filename: 'vendors.js', //拆分后打包的文件名字
      },
      default: {//像文件中 import进来的文件 如果不在 node_modules文件夹中 则走默认组,打包出的文件名字是 common.js
        priority: -20,
        reuseExistingChunk: true,//比如a.js 引用了 b.js;如果b.js在之前已经被拆分过,则这里不再对其进行拆分
        filename: 'common.js'
      }
    }
  }
}

转载于:https://www.cnblogs.com/xiaozhumaopao/p/10658920.html

你可能感兴趣的:(webpack学习笔记(二))