webpack书本总结,入门webpack必备

Posted lin-fighting

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack书本总结,入门webpack必备相关的知识,希望对你有一定的参考价值。

  • 观看了《webpack实践,进阶调优》的书本,记下了一下认为重要的笔记,可能对你也有用

正文开始:

commonjs与esmodule区别:

  • 1 commonjs模块依赖关系的建立发生在代码运行阶段; esmodule模块依赖关系的建立发生在代码编译阶段

​ - esmodule的优点

​ 1 esmodule可以“死代码检测和排除”通过静态分析可以在打包时去掉这些未曾使用过的模块,以减小打包资源体积。

​ 2 模块变量类型检查 ES6 Module的静态模块结构有助于确保模块之间传递的值或接口类型是正确的。

​ 3 编译器优化 在CommonJS等动态模块系统中,无论采用哪种方式,本质上导入的都是一个对象,而ES6 Module支持直接导入变 量,减少了引用层级,程序效率更高。

  • 2 值拷贝和动态映射

    commonjs得到的是一个值的拷贝,可以看做 const a = require(xx) = const a = module.exports。 a直接指向了exports这个对象. 的地址。如果是原始对象,那么源文件的值修改了,引用的引文的值并不会改变 因为他们是值的拷贝,并不是映射。

    而esmodule则是值的映射,并且映射是只读的。即使export const a = 1, import a from ‘x’,这里的a是对原🈶值的动态映射,也 就是当源文件a改变了,引入的这个a也会改变。但是不能在引入的文件

​ 对映射值更改,可以理解成一个笼子加一张网,透过网可以看到里面的实时景像,但是不能通过网去更改里面的东西。

  • 3 循环依赖

​ commonjs的循环依赖没有办法获取预期得到的结果。比如

// a.js
  const b = require('./b')
 console.log('b', b)
 module.exports =  a: 1 
 // b.js
 const a = require('./a')
 console.log('a', a)
  module.exports =  b: 2 
// index.js
  require('./a.')

正确的打印顺序应该是: ‘a’ : ; ‘b’: b:2

原因就是:看webpack的require实现原理

       const cache = 
       function require(moduleId)
           if(cache[moduleId])
               // 已经加载过的直接到导出exports对象
               return cache[moduleId].exports
           
           var module = exports: 
           cache[moduleId] = module // 缓存
           // ..执行该模块的代码给module赋值
           // ...
          	return module.exports
      

commonjs使用了cache缓存,当加载过的时候会将模块缓存起来,第一次index.js就已经加载了a文件。a文件加载b文件,控制权到b文件,此时又去加载a文件,cache已经有a了,直接返回module.exports 而此时a文件还没执行完毕,exports对象指向的是,就导致这种结果了。

esmoudle循环加载呢?

​ 打印结果是: ‘a’, undefined ; ‘b’: b:2

​ esmodule还是没能获取正确的值。原因也很简单,打印a的时候,此时a文件还没执行完毕,export default默认导出undefine,所以打印了undefined。

​ 但是esmodule的特点是动态映射,也就是说,只要我们在打印a的时候,使用setTimeout延迟,此时b文件执行完毕,导出b:2,然后a文件再导出a:1,最后再打印a的时候,因为动态映射的关系就可以正确打印出来了。

区别三点:1 静态动态分析 2 值拷贝和值映射 3 循环引用的区别。

webpack 概念理解

  • entry: 入口

  • chunk: 每个entry入口文件,以及他所存在依赖关系的模块,都会在打包的时候封装成一个chunk代码块。

    在Webpack中可以理解成被抽象和包装过后的一些模块。它就像一个装着很多文件的文件袋,里面的文件就是各个模块,Webpack在外面加了一层包裹,从而形成了chunk。多个入口有多个chunk生成。(特殊情况一个入口也可以有多个chunk)

  • bundle: chunk代码块打包后的文件称为bundle

资源输入和输出

  • entry

    可以是 string | array | object | function

    • 数组的作用是将多个资源预先合并,如
    module.exports = 
    entry: ['babel-polyfill', 'c', './src/index.js'] ,
    ;
    实际上是:
    module.exports = 
    entry: './src/index.js',
    ;
    
    // index.js
    import 'c'
    import 'babel-polyfill';
    

    会在最后一个index.js作为入口,然后前面的相当于在index.js中引入。

    • 对象,可以定义多入口,属性名就是chunk名。如

      module.exports = 
      entry: 
      index: ['babel-polyfill', './src/index.js'],
      lib: './src/lib.js',
      ,
      ;
      
    • 函数可以动态配置一些东西,也可以返回一个promise进行异步操作。

      module.exports = 
      entry: () => new Promise((resolve) => 
      // 模拟异步操作
      setTimeout(() => 
      resolve('./src/index.js');
      , 1000);
      ),
      ;
      
    • 应用:单页面应用和多页面应用

      1 单页面:只需要一个入口文件,公共模块提取vendor

      module.exports = 
      context: path.join(__dirname, './src'),
      entry: 
      app: './src/app.js',
      vendor: ['react', 'react-dom', 'react-router'],
      ,
      ;
      

      将一些第三方模块一起打包,vendor并没有设置入口文件,可以设置CommonsChunkPlugin(4之后废弃),改用了optimization.splitChunks了。后续再做笔记。

      2 多页面

      module.exports = 
      entry: 
      pageA: './src/pageA.js',
      pageB: './src/pageB.js',
      pageC: './src/pageC.js',
      vendor: ['react', 'react-dom'] ,
      ,
      ;
      

      也是需要配置optimizaiotn.splitChunks。

      当第三方依赖较多时,我们可以用提取vendor的方法将这些模块打包到一个单独的 bundle中,以更有效地利用客户端缓存,加快页面渲染速度。

  • output出口

    1 filename: 多个assets需要指定不同文件名,[hash] [chunkhash] [id] [name]

    output: 
    filename: '[name].js',
    ,
    

    这些变量用来: 1对chunk进行区分 2 控制客户端缓存,chunkhash/hash当chunk内容改变的时候改变,文件名跟着改变,用户下一次请求资源文件的时候,文件名改变导致只能重新下载新的版本,而不用本地缓存。

    一般用[name]@[chunkhash:8].js来进行命名,用于生产环境,开发环境则不需要。

    2: publicPath

    如果说path是用来指定资源的输出位置,那么publicPath就是用来指定资源的请求位置。

    一般用于三种情况

    1 html相关,可以指定publcikPath为html的相对路径,在请求的时候会以当前页面的index.html所在路径+相对路径,构成url,如
    值为 '', '.xx'或者以'.'开头的
    html地址:http://xx.com/app/index.html
    js文件名: a.js
    当publciPath: '', 实例的路径就是http:xx.com/app/a.js
    publicPath: './js', 世纪就是http:xx.com/app/js/a.js
    
    2 host相关,当值为'/'开头的,表示此时的publicPath以当前的host name为基础路径
    如
    publciPath: '/', 实际:http:xx.com/a.js
    publicPath: '/js/', 实际:http:xx.com/js/a.js
    
    3 cdn 绝对路径 publicPath以协议头或相对协议的形式
    publicPath: 'http://xx.cdn.com/', 实际就是http://.cdn.com/a.js
    

预处理器(loader)

loader赋予了webpack可处理不同资源类型的能力。

  • loader的本质:函数,webpack4之前,输入和输出都必须为字符串,4之后,loader也支持了抽象语法书AST的传递,从而减少重复的代码解析
output = loader(input)
// input可能是字符串,也可能是上一个loader的结果,包括转化后的字符串,sourcemap, AST对象。
// output也可能是转化后的字符串,sourcemap,ast对象。
module.exports = function loader (content, map, meta) 
var callback = this.async();
var result = handler(content, map, meta);
callback(
null, // error
result.content, // 转换后的内容
result.map, // 转换后的 source-map
result.meta, // 转换后的 AST
);
;

callback表示继续往下一个loader走,并传入对应参数。

  • loader options: loader作为预处理器通常会给开发者提供一些配置项,在引入loader的时候可以通过 options将它们传入
rules: [

test: /\\.css$/,
use: [
'style-loader',

loader: 'css-loader',
options: 
// css-loader 配置项
,

],
,
],
  • 更多配置:

    1 include & exclude 两者都存在,exclude权限更高

    2 resource与issuer,被加载模块和加载模块,exclude和include,test本质上属于对被加载者的配置。

    rules: [
    	
    		test: /\\.css$/,
    		use: ['style-loader', 'css-loader'],
    		exclude: /node_modules/,
    		issuer: 
    		test: /\\.js$/,
    		include: /src/pages/,
          ,
    	
    ],
    

    对加载者的限制,只有src下的pages下的js目录加载了css文件,规则才会生效,才会使用css-loader处理。

    3 enforce:指定loader的种类,只接收pre post。

    loader按照执行顺序分为: pre, inline(官方不推荐), normal, post四种类型。正常定义的loader都是noraml类型,可以通过enforce执行pre和post.

    如对eslint-loader,就可以设置为p re,这样就可以在所有loader之前先进行代码检查。也可以不适用enforce而是自己保证loader的顺序是正确的即可。

    enforce可以强制指定loader的作用顺序,可读性更强。

  • Babel-loader

    babel-loader用来处理ES6+并将其编译为ES5,

    npm install babel-loader @babel/core @babel/preset-env
    

    babel-loader:它是使Babel与Webpack协同工作的模块 babel工作的环境。

    @babel/core:它是Babel编译器的核心模块, 用来转换代码。

    @babel/preset-env:它是Babel官方推荐的预置器,可根据用户设置的目标环境自动 添加所需的插件和补丁来编译ES6+代码,作用就是较core怎么转化。

    rules: [
    	
    		test: /\\.js$/,
    		exclude: /node_modules/,
    		use: 
    			loader: 'babel-loader',
    			options: 
    				cacheDirectory: true,
    				presets: [[
    				'env', 
    				modules: false,
    			
    		]],
    		,
    		,
    	
    ],
    

    cacheDirectory配置项启用缓存机制,可以接受一个路径,为true的时候,缓存目录为node_modules/.cache/babel-loader

    preset-env会默认将esModule打包成commons,modules为false表示不转化,用于后期tree-shaking。

    babel-loader支持从.babelrc文件读取Babel配置,因此可以将presets和plugins从 Webpack配置文件中提取出来,也能达到相同的效果。

  • ts-loader 他的配置项不在ts-loader中,而必须放入工程目录下的tsconfig.json中。

  • Html-load 将htmlt转为字符串,然后通过document.wirte写入到文档中。

  • file-loader默认以output的publicPath为路径,现在使用webpack5的asset了。

  • 自定义loader loader的实现就是一个函数,

    // loader.js
    module.exports = function(content) 
    if(this.cacheable)
    	this.cacheable() 
    
    var useStrictPrefix = '\\'use strict\\';\\n\\n';
    return useStrictPrefix + content;
    
    
    rules: [
    	
    		test: /\\.js$/,
    		use: 
    			loader: 'force-strict-loader',
    			options: 
    				sourceMap: true,
    				,
    		,
    
    ],
    

    这样就完成了一个lo ader,他的作用是在打包出来的文件前面加上严格模式。webpack可以使用htis.cacheable控制缓存,当文件和其他依赖没有变化的时候,不应该重复进行转换工作。

    loader本质上是一个函数。第一个loader的输入是源文件,之后所有loader的输入是上 一个loader的输出,最后一个loader则直接输出给Webpack。

样式

  • PostCSS

    使用postcss-loader可以轻松地将PostCSS与Webpack连接起来。使用npm进行安装。

    module: 
    rules: [
    
    test: /\\.css/,
    use: [
    'style-loader',
    'css-loader',
    'postcss-loader',
    ] ,
    
    ],
    ,
    

    postcss要求有一个单独的配置文件,借助postcss-preset-env预设,自动添加前缀。配合stylelint检查样式

    const postcssPresetEnv = require("postcss-preset-env");
    const stylelint = require('stylelint');
    module.exports = 
      plugins: [
        postcssPresetEnv(
          browsers: "last 5 version",
        ),
        stylelint(
    			config: 
    			rules: 
    				'declaration-no-important': true,
    						,
    					,
    			)
      ],
    ;
    
    
  • Css-module ,

    module: 
      rules: [
        
          test: /\\.css/,
          use: [
            "style-loader",
            
              loader: "css-loader",
              options: 
                modules: true,
                localIdentName: "[name]__[local]__[hash:base64:5]",
              ,
            ,
          ],
        ,
      ];
    
    
    

    通过css-module开启modules开关,就可以启动模块化样式,localIdentName决定了转化后的类名,如

    // style.css
    .titke 
    	color: red;
    
    

    转化后的类型就是style_title_xxxx [name]是chunk名字, [local]是原本选择器表示符号,[hash]是hash值

以上是关于webpack书本总结,入门webpack必备的主要内容,如果未能解决你的问题,请参考以下文章

webpack入门--前端必备

不会webpack的前端可能是捡来的,万字总结webpack的超入门核心知识

webpack使用入门及常用配置总结

时下最流行前端构建工具Webpack 入门总结

webpack入门——构建简易版vue-cli

JavaScript系列文章:React总结之Webpack模块组织