Giter Site home page Giter Site logo

play-webpack's People

Contributors

ravencrown avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

play-webpack's Issues

webpack 优化用法之 体积分析

webpack-bundle-analyzer 插件

  1. 分析依赖的第三方模块文件大小
  2. 业务里面的组件的组件代码大小
  3. 127.0.0.1:8888 访问

配置

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
 
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

效果

image

github 地址

webpack 进阶用法之 自动清理构建目录产物

自动清理构建目录产物

每次构建的时候webpack不会自动清理目录,造成构建的输出目录 output 文件越来越多
所以可以在每次构建之前,删除下目录下的文件,可以通过 npm script 清理构建目录

$ rm -rf ./dist && webpack
$ rimraf ./dist && webpack

也可以采用 webpack 提供的 clean-webpack-plugin,默认会删除 output 指定的输出目录。使用插件可以避免每次构建前手动删除dist目录

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name][chunkhash:8].js'
    },
    plugins:[
        new CleanWebpackPlugin()
    ]
};

webpack 基础用法之 资源解析

url-loader

url-loader 即可以处理图片,也可以处理字体,可以设置较小资源base64

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /.(png|jpg|gif|jpeg)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10240
                        }
                    }
                ]
            }
        ]
    }
};

webpack 优化用法之 速度分析

speed-measure-webpack-plugin 插件

  1. 查看每一个loader或者是每一个插件的执行耗时
  2. 分析整个打包总耗时
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
 
const smp = new SpeedMeasurePlugin();
 
const webpackConfig = smp.wrap({
  plugins: [
    new MyPlugin(),
    new MyOtherPlugin()
  ]
});

效果

image

github 地址

webpack 进阶用法之 tree-shaking

tree-shaking (摇树优化)

概念:1个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打包到bundle 里面去,tree shaking 就是只把只用到的方法打入bundle,没用到的方法会在 ugligy 阶段被擦除掉

使用:webpack 默认支持,在 .babelrc 里设置 modules:false 即可,mode=production 的情况下默认开启

要求:必须是 ES6 的语法,CJS(common js) 的方式不支持

DCE(Dead code elimination)原理 - tree-shaking 用到了DCE原理

  • 代码不会被执行,不可到达
  • 代码执行的结果不会被用到
  • 代码只会影响死变量(只写不读)
if (false) {
   console.log("这段代码永远不会被执行")
}

Tree-shaking 原理

利用 ES6 模块的特点

  • 只能作为模块的顶层语句出现
  • import 的模块名只能是字符串常量
  • import binding 是 immutable

代码擦除:tree-shaking会对无用代码作比较,然后在 uglify 阶段删除无用代码。

webpack 基础用法之 CSS 解析

css 解析

使用两种loader

  • css-loader ⽤用于加载 .css ⽂文件,并且转换成 commonjs 对象
  • style-loader 将样式通过 <style> 标签插⼊入到 head 中
  • less-loader 用于将 less 转换为 css
module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /.less$/,       // less-loader 用于解析 less
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader'  
                ]
            },
        ]
    }
};

webpack 核心概念之 entry/output

entry用法

entry 是webpack的入口,支持单页面和多页面的形式

// 单页面, entry是一个字符串
module.exports = {
    entry: './path/to/my/entry/file.js'
};

// 多页面,entry 是一个对象
module.exports = { 
    entry: {
        app: './src/app.js',
        adminApp: './src/adminApp.js' 
    }
};

output用法

output 用来告诉webpack如何将编译后的文件输出到磁盘

// 单入口配置
module.exports = {
    entry: './path/to/my/entry/file.js',
    output: {
        filename: 'bundle.js’,
        path: __dirname + '/dist' 
    }
};

// 多入口配置
module.exports = { 
    entry: {
        app: './src/app.js',
        search: './src/search.js' 
    },
    output: {
        filename: '[name].js', path: __dirname + '/dist'
    } 
};

webpack 基础用法之 文件指纹

文件指纹

Hash: 和整个项目的构建有关,只要项目的文件有修改,整个项目构建的 hash 值就会更改
ChunkHash:和 webpack 打包的 chunk 有关,不同的 entry 会生成不同的 chunkhash 值
Contenthash:根据文件的内容来定义 hash,文件内容不变,则 contenthash 不变

JS 的文件指纹
设置 output 的 filename,使用 chunkhash

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name][chunkhash:8].js'
    }
};

CSS 文件指纹
设置MiniCssExtractPlugin的filename,使用contenthash

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name][chunkhash:8].js'
    },
    plugins:[
        new MiniCssExtractPlugin({
            filename: '[name]_[contenthash:8].css'
        })
    ]
};

图片文件的指纹设置

设置 file-loader 的filename,使用【hash】

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /.(png|jpg|gif|jpeg)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            name: 'img/[name][hash:8].[ext]'
                        }
                    }
                ]
            }
    },

};

image

webpack 基础用法之 文件监听和热更新

文件监听

文件监听是在发现源码发生变化时,⾃动重新构建出新的输出文件。

webpack 开启监听模式,有两种⽅式:

  • 启动 webpack 命令时,带上 --watch 参数
  • 在配置 webpack.config.js 中设置 watch: true

使用

{
    "name": "hello-webpack", 
    "version": "1.0.0", 
    "description": "Hello webpack", 
    "main": "index.js",
    "scripts": {
        "build": "webpack ",
        "watch": "webpack --watch"
    },
    "keywords": [], 
    "author": "", 
    "license": "ISC"
}

原理监听分析:轮询判断⽂件的最后编辑时间是否变化,某个文件发生了变化,并不会立刻告诉监听者,⽽是先缓存起来,等 aggregateTimeout

image

热更新之 webpack-dev-server

  • WDS 不刷新浏览器器
  • WDS 不输出⽂件,而是放在内存中
  • 使⽤ HotModuleReplacementPlugin插件
{
    "name": "hello-webpack",
    "version": "1.0.0",
    "description": "Hello webpack",
    "main": "index.js",
    "scripts": {
        "build": "webpack ",
        "dev": "webpack - dev - server--open"
    },
    "keywords": [],
    "author": "",
    "license": "ISC"
}

热更新之 webpack-dev-middleware

WDM 将 webpack 输出的文件传输给服务器器,适⽤用于灵活的定制场景

const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev- middleware');
const app = express();
const config = require('./webpack.config.js'); const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, { 
  publicPath: config.output.publicPath
}));
app.listen(3000, function () {
  console.log('Example app listening on port 3000!\n');
});

热更新的原理解析

image

webpack 核心概念之 mode

Mode 模式

Mode 可以用来指定当前的打包方式是:production、development还是none
设置 Mode 可以使用 webpack 的内置函数,默认值为production

Mode 的内置函数功能

image

webpack 进阶用法之 source map 使用

source map 使用

source map 的作用是定位webpack打包之后的bundle文件的源码位置,科普请看这篇文章JavaScript Source Map 详解

开发环境开启,线上环境关闭:线上排查问题的时候可以将sourcemap 上传到错误监控系统

sourcemap 关键字

  • eval: 使用eval包裹模块代码
  • source mao: 产生 .map 文件
  • cheap: 不包含列信息
  • inline: 将 .map 作为DataUrl 嵌入,不单独生成 .map 文件
  • module: 包含loader的sourcemap

source map 类型

image

eval 效果

eval 把模块代码包裹住,并且结尾使用 sourceURL 指向模块代码的文件
image

source-map 效果
源文件和 .map 文件分开,源文件结尾有sourceMappingUrl 标志,如图

image

inline-source-map 效果

文件不分离,把sourcemap inline进入了源文件,源文件大小变大。

image

webpack 基础用法之 HTML/CSS/JS 压缩

HTML/CSS/JS 的压缩

JS压缩:采用内置的 uglifyjs-webpack-plugin

CSS压缩
使用 optimize-css-assets-webpack-plugin,同时使用 cssnano

new OptimizeCSSAssetsPlugin({
  assetNameRegExp: /\.css$/g,
  cssProcessor: require('cssnano')
})

HTML 压缩

设置 html-webpack-plugin

    new HtmlWebpackPlugin({
        template: path.join(__dirname, 'src/search.html'),
        filename: 'search.html',
        chunks: ['search'],
        inject: true,
        minify: {
            html5: true,
            collapseWhitespace: true,
            preserveLineBreaks: false,
            minifyCSS: true,
            minifyJS: true,
            removeComments: false
        }
    })  

webpack 基础用法之 图片解析

解析图片 file-loader

file-loader ⽤用于处理理⽂文件

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /.(png|jpg|gif|jpeg)$/,
                use: 'file-loader'
            }
        ]
    }
};

webpack 进阶用法之 构建异常和中断处理

构建异常和中断处理

如何判断构建是否成功

  1. 在 CI/CD 的pipeline 或者发布系统需要知道当前的构建状态
  2. 每次构建完后输入 echo $? 获取错误码

webpack4 之前的版本构建失败不会抛出错误码(error code)

nodejs 中的 process.exit 规范

  • 0 表示成功完成,回调函数中,err 为null
  • 非 0 表示执行失败,回调函数中,err不为null,err.code 就是传给 exit 的数字

如何主动捕获并处理构建错误

  1. compiler 在每次构建结束之后会触发 done 这个hook
  2. process.exit 主动处理构建报错
// webpack 配置 plugin
plugins: [
    function() {
        this.hooks.done.tap('done', (stats) => {
            if (stats.compilation.errors && stats.compilation.errors.length && process.argv.indexOf('--watch') == -1)
            {
                console.log('build error');
                process.exit(1);
            }
        })
    }    
]

webpack 基础用法之 ES6 解析

ES6 解析

步骤1:配置.babelrc

{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins": [
        "@bable/proposal-class-properties"
    ]
}

步骤2:配置webpack loader

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /.js$/,
                use: 'babel-loader'
            }
        ]
    }
};

webpack 进阶用法之 优化构建时命令行的显示日志

优化构建时命令行的显示日志

webpack 打包展示一堆日志,很多并不需要开发者关注

统计信息 stats

image

优化命令行的构建日志

使用 friendly-errors-webpack-plugin 插件

  • success: 构建成功的日志提醒
  • warning: 构建警告的日志提示
  • error: 构建报错的日志提示
module.exports = { 
    entry: {
        app: './src/app.js',
        search: './src/search.js' 
    },
    output: {
        filename: '[name][chunkhash:8].js', 
        path: __dirname + '/dist'
    },
    plugins: [
        new FriendlyErrorsWebpackPlugin()
    },
    stats: 'errors-only'   //  设置 stats
}

webpack 基础用法之 JSX 解析

解析 JSX

步骤1:配置.babelrc

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ],
    "plugins": [
        "@bable/proposal-class-properties"
    ]
}

webpack 进阶用法之 提取公共资源

webpack 提取公共资源

基础库分离:React示例

思路:将react、react-dom 基础包通过cdn引入,不打入bundle
方法:使用html-webpack-extends-plugin

const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
plugins: [
    new HtmlWebpackExternalsPlugin({
        externals: [
          {
            module: 'react',
            entry: 'https://11.url.cn/now/lib/16.2.0/react.min.js',
            global: 'React',
          },
          {
            module: 'react-dom',
            entry: 'https://11.url.cn/now/lib/16.2.0/react-dom.min.js',
            global: 'ReactDOM',
          },
        ]
    }),
]

效果如图
image

使用 SplitChunksPlugin 进行公共脚本分离

webpack4 内置的,替代 CommonsChunkPlugin(webpack3使用的多) 插件,SplitChunksPlugin介绍请参考官方文档

chunks参数说明:

  • async: 异步引入的库进行分离(默认)
  • initial: 同步引入的库进行分离
  • all: 所以引入的库进行分离(推荐)
module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 30000, // 分离包体积的大小
      maxSize: 0,
      minChunks: 2,    // 设置最小引用次数为2次
      maxAsyncRequests: 5,  
      maxInitialRequests: 3,
      automaticNameDelimiter: '~',
      automaticNameMaxLength: 30,
      name: true,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,  // 匹配出需要分离的包
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  }
};

webpack 进阶用法之 Scope Hoisting

Scope Hoisting 使用和原理分析

现象:构建后的代码存在大量的闭包代码

image

会导致什么问题?

  • 大量函数闭包包裹代码,导致体积增大(模块越多越明显)
  • 运行代码时创建的函数作用域变多,内存开销变大

webpack模块转换分析

如图

image

结论

  • 被 webpack 转换后的模块会带一层包裹
  • import 会被转换成 __webpack_require

进一步分析 webpack 的模块机制

image

分析以上代码

  • 打包出来的是一个 IIFE(匿名闭包)
  • modules 是一个数组,每一项是一个模块化初始化函数
  • __webpack_require 用来加载模块,返回 module.exports
  • 通过 WEBPACK_REQUIRE_MOTHOD(0) 启动程序

scope hoisting 原理

原理:将所有的模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突

对比:通过 scope hoisting 可以减少函数声明代码和内存开销

image

scope hoisting 使用

  • webpack mode 为production 默认开启
  • 必须是 ES6 语法,CJS 不支持

可以参考官网对mode的描述,mode=production模式下自动开启FlagDependencyUsagePlugin , FlagIncludedChunksPlugin , ModuleConcatenationPlugin , NoEmitOnErrorsPlugin , OccurrenceOrderPlugin , SideEffectsFlagPlugin and TerserPlugin

image

module.exports = { 
    entry: {
        app: './src/app.js',
        search: './src/search.js' 
    },
    output: {
        filename: '[name][chunkhash:8].js', 
        path: __dirname + '/dist'
    },
    plugins: [
        new webpack.optimize.ModuleConcatenationPlugin() 
    };
}

webpack 进阶用法之 和ESLint 结合

webpack 和ESLint 结合

行业里面优秀的 ESLint 规范实践

ESLint 中文官网

Airbnb: eslint-config-airbnb、 eslint-config-airbnb-base

腾讯

指定团队的 ESLint 规范

  • 不重复造轮子,基于 eslint:recommend 配置并改进
  • 能够帮助发现代码错误的规则,全部开启
  • 帮助保持团队的代码风格统一,⽽不是限制开发体验

image

方案一:webpack 和 CI/CD 集成

image

本地开发阶段增加 precommit 钩子

  1. 安装 husky
$ npm install husky --save-dev
  1. 增加 npm script,通过 lint-staged 增量检查修改的文件
"scripts": {
    "precommit": "lint-staged"
}, 
"lint-staged": {
    "linters": {
        "*.{js,scss}": ["eslint --fix", "git add"] 
    }
}

方案二:webpack 和 ESLint 集成

使用 eslint-loader,构建时检查 JS 规范

module.exports = {
    module: {
        rules: [{
                test: /\.js$/,
                exclude: /node_modules/,
                use: [
                    "babel-loader",
                    "eslint-loader"
                ]
            }
        };
    ]
}

.eslintrc.js 文件配置

module.exports = {
    "parser": "babel-eslint",  // 解释器
    "extends": "airbnb",         // 继承airbnb规则
    "env": {                             // 设置环境,当前设置了浏览器和node环境
        "browser": true,
        "node": true
    },
    "rules": {
        "indent": ["error", 4]
    }
};

webpack 进阶用法之 PostCSS 插件 autoprefixer 自动补齐 css3前缀

PostCSS 插件 autoprefixer 自动补齐 css3前缀

CSS3属性为什么需要前缀?

因为:浏览器内涵版本不一样

image

webpack 的PostCSS配置如下

  module: {
        rules: [
            {
                test: /.less$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'less-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: () => [
                                require('autoprefixer')({
                                    browsers: ['last 2 version', '>1%', 'ios 7']
                                })
                            ]
                        }
                    }
                ]
            }
        ]
    },

webpack 进阶用法之 多页面(MPA)应用打包方案

多页面(MPA)应用打包方案

在webpack里,每个页面对应一个 entry,一个html-webpack-plugin。
缺点:每次新增或删除页面都需要修改 webpack 配置。

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    }
};

解决方案1:动态获取 entry 和设置 html-webpack-plugin 数量

解决方案2:利用 glob.sync

glob库

entry: glob.sync(path.join(__dirname, './src/*/index.js'))

这两个解决方案的前提是把入口文件放到 /src/*/index.js 下,所以的入口文件都叫index.js,通过二级目录来区分。

module.exports = {
    entry: {
        index: './src/index/index.js',
        search: './src/search/index.js'
    }
};

如果使用glob库的话,

const setMPA = () => {
    const entry = {};
    const htmlWebpackPlugins = [];
    const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));

    Object.keys(entryFiles)
        .map((index) => {
            const entryFile = entryFiles[index];
            // '/Users/cpselvis/my-project/src/index/index.js'

            const match = entryFile.match(/src\/(.*)\/index\.js/);
            const pageName = match && match[1];

            entry[pageName] = entryFile;
            htmlWebpackPlugins.push(
                new HtmlWebpackPlugin({
                    inlineSource: '.css$',
                    template: path.join(__dirname, `src/${pageName}/index.html`),
                    filename: `${pageName}.html`,
                    chunks: ['vendors', pageName],
                    inject: true,
                    minify: {
                        html5: true,
                        collapseWhitespace: true,
                        preserveLineBreaks: false,
                        minifyCSS: true,
                        minifyJS: true,
                        removeComments: false
                    }
                })
            );
        });

    return {
        entry,
        htmlWebpackPlugins
    }
}

webpack 基础用法之 字体解析

解析字体 file-loader

file-loader 也可以⽤于处理字体

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /.(woff|woff2|eot|ttf|otf)$/,
                use: 'file-loader'
            }
        ]
    }
};

webpack 核心概念之 loader/plugin

Loaders

webpack 开箱即用只支持JS和JSON两种格式,通过loader去支持其他文件类型并且把他们转化为有效的模块,并且可以添加到依赖图中。

loader本身是一个函数,接受源文件为参数,返回转换的结果

常见的loader有

名称 描述
bable-loader 转换ES6/ES7等新特性语法
css-loader 支持.css 文件的加载和解析
less-loader 将less文件转换为css
ts-loader 将TS转换为JS
file-loader 进行图片、字体的打包
raw-loader 将文件以字符串的形式导入
thread-loader 多进程打包JS和CSS

Loaders 的用法

// 配置示例
const path = require('path');
module.exports = {
    output: {
        filename: 'bundle.js'
    },
    module: {
        rules: [{
            test: /\.txt$/,          // test 指定匹配规则
            use: 'raw-loader'  // use 指定使用的 loader 名称
        }]
    }
};

Plugins

插件用于bundle文件的优化,资源管理和环境变量注入,作用于整个构建过程

常见的plugins

image

Plugins 的用法

const path = require('path');
module.exports = {
    output: {
        filename: 'bundle.js'
    },
    plugins: [  // 放在plugins 数组中
        new HtmlWebpackPlugin({
            template: './src/index.html'
        })
    ]
};

webpack 进阶用法之 静态资源内联

静态资源内联

资源内联的意义

代码层面

  • 页面框架的初始化脚本
  • 上报相关打点
  • css 内联避免页面闪动

请求层面:减少HTTP网络请求数

  • 小图片或者字体内联(url-loader)

raw-loader 内联 HTML

<script>${require('raw-loader!babel-loader!./meta.html')}</script>

raw-loader 内联 JS

<script>${require('raw-loader!babel-loader!../node_modules/lib-flexible')}</script>

css内联1 - style-loader

module.exports = {
    entry: {
        index: './src/index.js',
        search: './src/search.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /.scss$/,
                use: [
                    {
                        loader: 'style-loader',
                        options: [
                            insertAt: 'top', // 将样式插入到 <head>
                            singleton: 'true' // 将所有的 style 标签合成一个
                        ]
                    },
                    'css-loader',
                    'sass-loader'
                ]
            }
        ]
    }
};

css内联2 - html-inline-css-webpack-plugin

webpack 进阶用法之 移动端 CSS px 自动转化成 rem

移动端 CSS px 自动转化成 rem

首先先看下移动端的浏览器分辨率

image

px 自动装换成 rem可以使用 px2rem-loader,页面渲染时计算根元素的 font-size 值。也可以使用手淘的lib-flexible插件

webpack 配置如下

module: {
    rules: [
        {
            test: /.less$/,
            use: [
                MiniCssExtractPlugin.loader,
                'css-loader',
                'less-loader',              
                {
                    loader: 'px2rem-loader',
                    options: {
                        remUnit: 75,   // 1rem = 75px
                        remPrecision: 8  // 小数点位数
                    }
                }
            ]
        }
    ]
},

Lib-flexible 的源码, 短短不到一百行

动态的计算根元素的rem单位。

(function flexible (window, document) {
  var docEl = document.documentElement

  //window.devicePixelRatio获取设备像素比(设备像素比 = 物理像素 / 设备独立像素)
  var dpr = window.devicePixelRatio || 1 

  // adjust body font size
  // 根据 dpr 设置body 下的font-size
  function setBodyFontSize () {
    if (document.body) {
      document.body.style.fontSize = (12 * dpr) + 'px'
    }
    else {
      document.addEventListener('DOMContentLoaded', setBodyFontSize)
    }
  }
  setBodyFontSize();

  // set 1rem = viewWidth / 10
  // 根据页面宽度设置 rem 的单位
  function setRemUnit () {
    var rem = docEl.clientWidth / 10
    docEl.style.fontSize = rem + 'px'
  }

  setRemUnit()

  // reset rem unit on page resize
  //在窗口大小改变之后,就会触发resize事件.
  //当一条会话历史记录被执行的时候将会触发页面显示(pageshow)事件
  window.addEventListener('resize', setRemUnit)
  window.addEventListener('pageshow', function (e) {
    if (e.persisted) {
      setRemUnit()
    }
  })

  // detect 0.5px supports
  // 当dpr >=2的时候设置border为0.5px 
  if (dpr >= 2) {
    var fakeBody = document.createElement('body')
    var testElement = document.createElement('div')
    testElement.style.border = '.5px solid transparent'
    fakeBody.appendChild(testElement)
    docEl.appendChild(fakeBody)
    if (testElement.offsetHeight === 1) {
      docEl.classList.add('hairlines')
    }
    docEl.removeChild(fakeBody)
  }
}(window, document))

webpack 进阶用法之 代码分割和动态import

代码分割和动态import

对于大的Web应用来讲,将所有的代码都放在一个文件中显然不够有效的,特别是当你的某些代码块是在某些特殊情景下才会被使用到。webpack有一个功能就是将你的代码库分割成chunks(语块),当代码运行到需要它们的时候再进行加载。

适用场景

  • 抽离相同代码到一个共享块
  • 脚本懒加载,使得初始下载的代码更小

image

懒加载 JS 脚本的方式(用到这个脚本再加载它)

  • CommonJS:require.ensure
  • ES6:动态import(目前没有原生支持,需要babel转换)

如何使用动态import

  1. 安装 babel 插件
$ npm install @babel/plugin-syntax-dynamic-import --save-dev
  1. ES6:动态import
// .babelrc 文件配置
{
    'plugins:['@babel/plugin-syntax-dynamic-import']'
}

代码分割效果

import React from 'react';
import ReactDOM from 'react-dom';
import largeNumber from 'large-number';
import logo from './images/logo.png';
import './search.less';

class Search extends React.Component {

    constructor() {
        super(...arguments);

        this.state = {
            Text: null
        };
    }
    // 动态import 关键代码
    loadComponent() {
        import('./text.js').then((Text) => {
            this.setState({
                Text: Text.default
            });
        });
    }

    render() {
        const { Text } = this.state;
        const addResult = largeNumber('999', '1');
        return <div className="search-text">
            {
                Text ? <Text /> : null
            }
            { addResult }
            搜索文字的内容<img src={ logo } onClick={ this.loadComponent.bind(this) } />
        </div>;
    }
}

ReactDOM.render(
    <Search />,
    document.getElementById('root')
);

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.