几种基本用法

清理构建的目录

可以通过在执行构建的命令前加一句清除目录的命令
如在package.json里面的build命令修改为

"scripts": {
    build: rm -rf ./dist && webpack
}

比较常用的是通过webpack的插件实现

const { CleanWebpackPlugin }  = require('clean-webpack-plugin')
modules.export = {
    plugins: [
         new CleanWebpackPlugin()
    ]
}

处理样式

我们需要添加css前缀来处理兼容性问题。通过配置postcss-loader来实现。注意是先添加前缀然后再把scss转换成css,所以要写在最下面。

 {
                test: /.scss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'sass-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: () => [
                                require('autoprefixer')({
                                    overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
                                })
                            ]
                        }
                    }
                ]
            },
modules.export = {
    plugins: [
        new OptimizeCssAssetsWebpackPlugin({
            assetNameRegExp: /\.css$/g,
            cssProcessor: require('cssnano')
        })
    ]
}

对于字体大小的兼容,我们可以使用rem作为字体的单位。但是把px转换成rem是一个比较麻烦的计算过程,而且需要对不同分辨率下的设备,设置不同的根元素字体大小,从而调整整体的字体大小。一个解决方案就是,在html页面引入flexible.js,再样式文件的loader里面添加px2rem-loader。
引入flexible.js,可以通过直接用script标签引入cdn的链接,也可以通过文件内联的形式,也就是把flexible.js里面的内容,直接嵌入到<script></script>中。这里只介绍内联方式。
由于我们使用的是html-webpack-plugin把html模板编译到dist下面,所以是支持ejs语法。需要babel-loader把文件的内容转换成兼容性好的代码,然后用raw-loader把文件内容输出成字符串。注意这里的raw-loader安装的是0.5版本。

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

这样我们打包出来的文件就是

<script>
   flexible.js的内容
</script>

添加px2rem-loader

{
        test: /.scss$/,
        use: [
            MiniCssExtractPlugin.loader,
            'css-loader',
            {
                loader: 'px2rem-loader',
                options: {
                    remUnit: 75, // 1px=75rem
                    remPrecision: 8 // 计算rem保留的精度
                }
            },
            'sass-loader',
            {
                loader: 'postcss-loader',
                options: {
                    plugins: () => [
                        require('autoprefixer')({
                            overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
                        })
                    ]
                }
            }
        ]
}

提取公共资源

多页应用通用打包方案

这里主要是通过动态获取要打包的page路径,生成entry和对应的html-webpack-plugin

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

    Object.keys(entryFiles).forEach((index) => {
        const entryFile = entryFiles[index]
        const match = entryFile.match(/src\/pages\/(.*)\/index\.js/);
        const pageName = match && match[1];
        entry[pageName] = `./src/pages/${pageName}/index.js`
        console.log(pageName)
        htmlWebpackPlugins.push(new HtmlWebpackPlugin({
            template: path.join(__dirname, `./src/pages/${pageName}/${pageName}.html`),
            filename: `${pageName}.html`,
            chunks: [pageName],
            inject: true,
            minify: {
                html5: true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: false
            }
        }))
    })

    return {
        entry,
        htmlWebpackPlugins
    }
}

const { entry, htmlWebpackPlugins } = setMAP()

modules.export = {
    entry,
    plugins: [
    ].concat(htmlWebpackPlugins)
}

基础库分离

一种方案是通过html-webpack-externals-plugin,然后在html里面直接引入组件库的cdn链接

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

html

<script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react.min.js"></script>
<script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react-dom.min.js"></script> 

另外一种方法是通过webpack4的
SplitChunksPlugins实现,顺便提一下,webpack3使用的是commonChunksPlugin

module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
            template: path.join(__dirname, `./src/pages/search/search.html`),
            filename: `search.html`,
            chunks: ['vendors', 'common', 'search'], //注意这里要引入vendors跟common
            inject: true,
            minify: {
                html5: true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: false
            }
        })
    ]
    optimization: {
        splitChunks: {
            minSize: 0,
            cacheGroups: {
                vendors: {
                    test: /(react|react-dom)/,
                    name: 'vendors',
                    chunks: 'all',
                    priority: -10   // 需要设置权重才能都分离出来
                },
                common: {
                    name: 'commons',
                    chunks: 'all',
                    minChunks: 2,
                    priority: -20   
                }
            }
        }
    },
}

代码动态分割和import

ES6还不支持这个功能,需要借助babel插件实现。

npm install @babel/plugin-syntax-dynamic-import --save-dev

在babel的配置文件.babelrc里面添加

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

使用的时候直接通过import函数引入某个组件

   loadComponent () {
        import("./text.js").then((Text) => {
            console.log(Text)
            this.setState({
                Text: Text.default // 注意这里设置的是Text.default
            })
        })  
    }

这样就可以发现,text.js被打包成一个独立的js,当触发loadComponent在浏览器的network里面才看到这个文件。

优化显示日志

我们在build的时候,可能只需要看到报错的日志,可以通过设置stats来控制要显示的日志。同时配合插件friendly-errors-webpack-plugin优化日志的输出。
stats参数:

modules.export {
    plugins: [
        new FriendlyErrorsWebpackPlugin()
    ],
    stats: 'errors-only'
}

打包组件跟库

react ssr简单demo

几个重要的概念

socucemap
tree shaking

概念:就是在构建的过程中,删除掉我们不需要用的代码。<br/>
优化原则:无用代码的判断,是根据DCE原则,某些代码不会被执行,或者是执行后的结果不会被用到,或者是执行的结果被用到的变量并没有被使用,这些代码都是无效代码,在tree-shaking中要被优化掉的。<br/>
执行阶段:这里是通过静态分析,在编译阶段实现的<br/>
特点:使用ES6的import方法引入文件是可以进行tree-shaking,require是动态引入的文件,无法进行tree shaking, 因为不会在运行的时候还去分析优化代码。<br/>
如何开启:webpack4的production模式是默认会开启tree-shaking的

scope hoisting

webpack在编译的时候,会把import进来的模块用闭包函数包裹,然后通过__webpack_require__的形式使用。这样会导致两个问题。<br/>
1、打包的代码体积比较大。<br/>
2、运行时的内存开销比较大。<br/>


scope hoisting通过把import进来的模块,直接内联到同一个闭包函数中,通过替换变量名的方式,避免代码冲突,来减少代码里面的闭包函数。但是需要注意的是仅仅对只被引入过一次的函数使用这个方案,对多次被引入的,我们还是希望它是一个独立的闭包模块,便于多次使用。

特点:仅在ES6的import下生效,动态引入的require模式下不起作用。<br/>
如何开启:webpack4的production模式是默认会开启tree-shaking的


supportlss
230 声望16 粉丝