webpack学习笔记

manifest

记录各个文件的identify id,在浏览器端控制页面资源加载,import和require都转换为_webpack_require_,通过使用 manifest 中的数据,runtime 将能够查询模块标识符,检索出背后对应的模块。

使用<script>标签在Index.html文件中引入包的缺点

  • 无法立即体现,脚本的执行依赖于外部扩展库(external library)。
  • 如果依赖不存在,或者引入顺序错误,应用程序将无法正常运行。
  • 如果依赖被引入但是并没有使用,浏览器将被迫下载无用代码。

注意,webpack 不会更改代码中除 importexport 语句以外的部分

通过 package.json 的 "sideEffects" 属性,来实现项目文件是否包含为引用函数(副作用)。告知webpack是否在打包时安全删除这些函数

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js",
    "*.css"
  ]
}

任何导入的文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似 css-loader 并导入 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除

import() 调用会在内部用到 promises

性能优化

把项目中的第三方库在打包时提取到一个单独的js中,方便客户端缓存,减少下次请求

shimming全局变量

  const path = require('path');
+ const webpack = require('webpack');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
-   }
+   },
+   plugins: [
+     new webpack.ProvidePlugin({
+       _: 'lodash'
+     })
+   ]
  };

构建性能

  • 保持webpack,node,npm或yarn的最新版本
  • 将Loader应用于最少数的必要模块中
  • 每个额外的 loader/plugin 都有启动时间。尽量少使用不同的工具。
  • 使用 DllPlugin 将更改不频繁的代码进行单独编译。
  • 减少编译的整体大小,以提高构建性能。尽量保持 chunks 小巧。
  • thread-loader 可以将非常消耗资源的 loaders 转存到 worker pool 中
  • 使用 cache-loader 启用持久化缓存。使用 package.json 中的 "postinstall" 清除缓存目录。

对development特别有用的方案

  • 增量编译。使用监听模式
  • 在内存中编译。
  • devtools选用
  • 避免在生产环境下才会用到的工具
  • 最小化chunk入口
  • 避免额外的优化步骤
  • ts-loader 开启transpileOnly

对poduction特别有用的方案

优化代码质量在大多数情况下比构建性能更重要。

  • Source maps 真的很消耗资源。你真的需要他们?

内容安全策略

目的

CSP 的主要目标是减少和报告 XSS 攻击 。一个CSP兼容的浏览器将会仅执行从白名单域获取到的脚本文件,忽略所有的其他脚本 (包括内联脚本和HTML的事件处理属性)。

用法

为使CSP可用,你需要配置你的网络服务器返回Content-Security-Policy

<meta>元素也可用来配置该策略

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

Content-Security-Policy-Report-Only不强制执行策略,只发送报告

nonce

  1. 后台生成nonce,至少128位数据的随机base64编码字符串

  2. 设置在对应的script/style nonce属性上

    <script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">…</script>
    
  3. 将第一步后台生成的nonce增加一个nonce-前缀,然后附加在后端生成的CSP 标头上

    Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
    

webpack能够为所有的脚本添加nonce,启用此功能,需要在引入的入口脚本中设置一个 __webpack_nonce__ 变量。

在 entry 文件中:

// ...
__webpack_nonce__ = 'c29tZSBjb29sIHN0cmluZyB3aWxsIHBvcCB1cCAxMjM=';
// ...

公共路径

publicPath能帮助你为项目中的所有资源指定一个基础路径

Service Worker

什么是Service Worker

Service Worker 是浏览器在后台独立于网页运行的脚本,它打开了通向不需要网页或用户交互的功能的大门。

service worker生命周期独立于网页

  1. 在页面javaScript中注册
  2. 浏览器在后台启动服务工作线程安装步骤。在安装过程中,您通常需要缓存某些静态资产。如果所有文件缓存成功,则安装成功。
  3. 激活。这是管理旧缓存的绝佳机会
  4. Service Worker 将会对其作用域内的所有页面实施控制,不过,首次注册该 Service Worker 的页面需要再次加载才会受其控制。

使用条件

  1. 浏览器支持
  2. 在开发过程中,可以通过 localhost 使用 Service Worker,但如果要在网站上部署 Service Worker,则需要在服务器上设置 HTTPS。

注册

if ('serviceWorker' in navigator)
    window.addEventListener('load', function () {
        navigator.serviceWorker.register('/sw.js').then(function (registration) {
            // Registration was successful
            console.log('ServiceWorker registration successful with scope: ', registration.scope);
        }, function (err) {
            // registration failed :(
            console.log('ServiceWorker registration failed: ', err);
        });
    })
})

sw.js文件位于根网域,Service Worker 将接收此网域上所有事项的 fetch 事件。如果我们在 /example/sw.js 处注册 Service Worker 文件,则 Service Worker 将只能看到网址以 /example/ 开头(即/example/page1//example/page2/)的页面的 fetch 事件。

安装

var CACHE_NAME = 'my-site-cache-v1';
var urlsToCache = [
    '/',
    '/styles/main.css',
    '/script/main.js'
];

self.addEventListener('install', function(event) {
    event.waitUtil(
        caches.open(CACHE_NAME).then(function(cache) {
            console.log('Opened cache');
            return cache.addAll(urlsToCache);
        })
    );
})

缓存和返回请求

// 缓存请求
self.addEventListener('fetch', function(event) {
    event.respondWith(
        caches.match(event.request).then(function(response) {
            if (response) {
                return response;
            }

            var fetchRequest = event.request.clone();

            return fetch(fetchRequest).then(function(response) {
                // 确保响应有效, 确保响应状态为200, 确保响应类型为basic, 即自身发起的请求。这意味着,对第三方资产的请求也不会添加到缓存
                if (!response || response.status !== 200 || response.type !== 'basic') {
                    return response;
                }

                //通过检查,则克隆响应。该响应是数据流,主体只能使用一次,所以先克隆
                var responseToCache = response.clone();

                caches.open(CACHE_NAME).then(function(cache) {
                    cache.put(event.request, responseToCache);
                });

                return response;
            })
            return fetch(event.request);
        })
    )
})

更新service worker

self.addEventListener('activate', function(event) {
    var cacheWhitelist = ['page-cache-v1', 'blog-posts-cache-v1'];

    event.waitUtil(
        caches.keys().then(function(cacheNames) {
            return Promise.all(
                cacheNames.map(function(cacheName) {
                    if (cacheWhitelist.indexOf(cacheName) === -1) {
                        return caches.delete(cacheName);
                    }
                })
            )
        })
    )
})
posted @ 2019-06-27 18:50  CodingSherlock  阅读(634)  评论(0编辑  收藏  举报