我爱编程

从0到1构建webpack4.1.0项目

2018-04-19  本文已影响235人  love_program

初始化项目

cnpm i webpack@4.1.0 webpack-cli@2.0.14 style-loader@0.21.0 css-loader@0.28.11  webpack-dev-server@3.1.3 -D
...
  "scripts": {
    "test": "webpack --mode development",//打包测试环境代码
    "build": "webpack --mode production" //打包开发生成环境代码
  },
...

webpack配置文件

module.exports = {
    entry:"./src/index.js" ,
    output: {
        path:path.join(__dirname, 'dist'),
        filename:'[name].[hash:8].js'
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                loader: ['style-loader','css-loader']
            },
            {
                test: /\.(png|jpg|gif|svg|bmp)/,
                use: {
                    loader: 'url-loader',
                    options:{
                        limit:9*1024,
                        //指定拷贝文件的输出目录
                        outputPath: 'images/'
                    }
                }
            },
            {
                test: /\.(html|htm)/,
                loader:'html-withimg-loader'
            },
            {
                test: /\.less$/,
                use: ['style-loader','css-loader', 'less-loader']
            },
            {
                test: /\.scss/,
                use: ['style-loader','css-loader', 'sass-loader']
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin([path.join(__dirname, 'dist')]),
        new HtmlWebpackPlugin({ 
            template: './src/index.html',
            filename: 'index.html',
            title: 'webpack',
            hash: true,
            chunks:['vendor', 'index'],
        }), 
    ],
    devServer: {
        contentBase: './dist',
        host: 'localhost',
        port:8080,
         //服务器返回给浏览器的时候是否启用gzip压缩
        compress: true,
    }
}

ps:

   {
       open:true,//自动打开浏览器
       inline:true,//在打包后文件里注入一个websocket客户端,监听文件变化,自动刷新
       contentBase: './dist', //指定静态文件的根目录
       host: 'localhost',//配置主机
       port:8080, //配置端口号,默认8080
       compress: true, //服务器返回给浏览器的时候是否启用gzip压缩
   }

配置webpack静态服务器

  1. 安装webpack-dev-server
    cnpm i webpack-dev-server@3.1.3 -D
  2. webpack.config.js文件配置
 "scripts": {
    //开启一个静态服务器
    //--open 自动打开浏览器
    "dev": "webpack-dev-server  --mode development " 
  },
  1. package.json文件需要添加的配置
    //配置静态服务器,可以预览打包后的项目
    devServer: {
        open:true,//自动打开浏览器
        //静态文件的根目录
        contentBase: './dist',
        //配置主机
        host: 'localhost',
        //配置端口号,默认8080
        port:8080,
        //服务器返回给浏览器的时候是否启用gzip压缩
        compress: true,
    }
  1. webpack-dev-server 打包后的文件是放在内存里面的,所以在硬盘里面是找不到这样的文件的

自动生成html文件

  1. 安装html-webpack-plugin插件
    cnpm i html-webpack-plugin@3.2.0
  2. src目录下面添加一个模板文件index.html
  3. 配置package.json文件
  plugins: [
        
        //此插件可以自动产出html文件,默认保存在output.path指定的目录下面
        new HtmlWebpackPlugin({
            
            //指定产出的html模板
            template: './src/index.html',
            //产出的html文件名称
            filename: 'index.html',
            //可以往模板里面传入自定义标题,模板默认使用ejs语法;所以可以在模板里面使用ejs语法,写入变量
            title: 'webpack',
            //会在插入的静态文件加上查询字符串,避免浏览器的缓存;如果是单入口文件的话,每次打包之后都是main.js,浏览器会有缓存,如果想去掉这个缓存的话,就可以加入查询字符串,避免浏览器的缓存
            hash: true,
            //在产出的html文件里面引入哪些代码块,里面的名字要跟entry里面key对应
       chunks:['index']
        })    
    ],
  1. 可以在模板文件里面以ejs语法写入传进去的变量
...
<head>
    <meta charset="UTF-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
...
  1. 生成的目标html文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webpack</title>
</head>
<body>
    
<script type="text/javascript" src="main.ef8b627c.js?ef8b627c68ea6ee379e1"></script></body>
</html>

构建的时候自动删除dist目录

  1. 安装clean-webpack-plugin插件
    cnpm i install clean-webpack-plugin@0.1.19 -D
  2. 配置webpack.config.js插件
plugins: [
  //删除dist目录
  new CleanWebpackPlugin([path.join(__dirname, 'dist')]),
]

引入第三方模块,以jquery为例

项目中图片的使用(css, js,html分别引入)

项目中less,sass的使用

  1. 安装less, less-loader, node-sass sass-loader
    cnpm i less@3.0.4 less-loader@4.1.0 node-sass@4.9.0 sass-loader@7.0.1 -D
  2. 配置webpack.config.js
   {
      test: /\.less$/,
      use: ['style-loader','css-loader', 'less-loader']
   },
   {
     test: /\.scss/,
     use: ['style-loader','css-loader', 'sass-loader']
   }

提取css文件

  1. 安装extract-text-webpack-plugin插件
    cnpm i extract-text-webpack-plugin@next -D
  2. 配置webpack.config.js
```
  //实例插件
 let cssExtract = new ExtractTextWebpackPlugin('css/css.css');//    
 传入的是打包后的文件名
 let lessExtract = new ExtractTextWebpackPlugin('css/less.css');
 let scssExtract = new ExtractTextWebpackPlugin('css/scss.css');

  ...
  //配置loader
   module: {
    rules: [
        {
            test: /\.css$/,
            use: cssExtract.extract({
                use: ['css-loader']
            })
        },
        {
            test: /\.less$/,
            use: lessExtract.extract({
                use: ['css-loader', 'less-loader']
            })
        },
        {
            test: /\.scss/,
            use: scssExtract.extract({
                use: ['css-loader', 'sass-loader']
            })
        }
    ]
},
  ...
  //配置插件
  plugins:[
     cssExtract,
     lessExtract,
     scssExtract
  ]
```

给css3添加前缀

  1. 安装postcss-loader autoprefix
    cnpm i postcss-loader autoprefixer -D
  2. 配置webpack.config.js
{
     test: /\.less$/,
     use: lessExtract.extract({
          //最后面添加一个postcss-loader
           use: ['css-loader', 'less-loader', 'postcss-loader']
      })
 },
  1. 在根目录下面新建postcss.config.js,里面的内容如下
module.exports = {
    plugins: [require('autoprefixer')]
}

压缩css

module:{
  rules:[
      {
           test: /\.less$/,
           use: lessExtract.extract({
                use: ['css-loader?minimize', 'less-loader', 'postcss-loader']
                })
        },
  ]
}

解析es6,es7代码

  1. 安装相关插件
 cnpm i babel-loader@7.1.4 babel-core@6.26.3 babel-preset-env@1.6.1 babel-preset-stage-0@6.24.1 babel-preset-react@6.24.1 -D
  1. 配置webpack.config.js
{
   test: /\.jsx?$/,
    use:[
            {
                loader: 'babel-loader'
            }
         ],

        //只转换或者编译src目录下面的文件
        include: path.join(__dirname,'./src'),
        //不用解析node_modules
        exclude:/node_modules/
},
  1. 在package.json同级目录下面放入.babelrc文件,内容如下
{
  "presets":["env", "stage-0"]
}

压缩js代码

  1. 安装uglifyjs-webpack-plugin插件
    cnpm i uglifyjs-webpack-plugin -D
  2. 配置webpack.config.js
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
...
plugins: [
   new UglifyjsWebpackPlugin(),
]

webpack.config.js配置devtool定位源码错误位置

  1. devtool:'source-map',//生成单独map文件,可以定位到哪一列出错了,定位的错误最准确, 但是体积最大
  2. devtool:'cheap-module-source-map',//生成单独文件,体积更小,但只能定位到哪一行出错了
  3. devtool:'eval-source-map',//不会生成单独文件,在文件的底部生成map文件进行映射,比较大
  4. devtool:'cheap-module-eval-source-map',//不会生成单独文件,只能定位到行

拷贝文件

  1. 安装copy-webpack-plugin 插件
    cnpm i copy-webpack-plugin -D
  2. 配置webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin');
...
plugins:[
  new CopyWebpackPlugin([{

        from:path.join(__dirname, 'src/public'),//源文件目录
        to:path.join(__dirname, 'dist/public')//目标目录
  }])
]

项目中引入bootstrap

  1. 安装bootstrap
    cnpm i bootstrap -D
  2. 配置webpack.config.js
resolve:{
        //配置扩展名, 引入模块的时候可以不加扩展名,加载顺序从前往后
        extensions:[".js", ".json"],
        //配置别名,在js里面直接引用
        alias:{
            "bootstrap":"bootstrap/dist/css/bootstrap.css"
        }
 },
module:{
    rules:[
        {
          //匹配的文件添加eot|woff|woff2|ttf用来处理字体文件
           test: /\.(png|jpg|gif|svg|bmp|eot|woff|woff2|ttf)/,
           use: {
               loader: 'url-loader',
               options:{
                        limit:9*1024,
                        outputPath: 'images/'
                    }
                }
            },
    ]
}
  1. 项目中加载bootstrap
    require('bootstrap')
  2. 引入的bootstrap因为加载的是以css为扩展,所以最终会被以下loader处理,文件最终会被提取到css.css文件里面,放到目标目录
{
   test: /\.css$/,
   use: cssExtract.extract({
         use: ['css-loader?minimize']
    })
},

项目中使用react

  1. 安装react react-dom babel-core babel-loader
    cnpm i react react-dom babel-core babel-loader -D
  2. 配置webpack.config.js
{
 test: /\.jsx?$/,
 use:[
         {
              loader: 'babel-loader'
          }
        ]
},
  1. 在与package.json同级目录新建.babelrc文件,内容如下
{
  "presets":["env", "stage-0", "react"]
}
  1. 项目中使用
import React from 'react';
import ReactDom from 'react-dom';

ReactDom.render(<h1>hello world</h1>, document.getElementById('root'));

(优化)配置resolve减少模块搜索范围

resolve:{
        //加载模块的时候,会到下面指定的目录查找
        modules:['node_modules','./libs'],
        //当加载的模块是包的时候,找的入口文件是package.josn里面的main字段,如果没有会依次找browser,node字段; 主要是用来加载同一个api,但是区分不同的平台
        mainFields:['main', 'browser', 'node'],
        //配置扩展名, 引入模块的时候可以不加扩展名,加载顺序从前往后
        extensions:[".js", ".json"],
        //配置别名,在js里面直接引用
        alias:{
            //当加载第三方模块的时候,直接加载编译过后的代码,不会再去区分环境加载不同的代码
            react:'react/cjs/react.production.min.js',
            "bootstrap":"bootstrap/dist/css/bootstrap.css",
            vue: 'vue/dist/vue.js'
        }
    },

(优化)module.noParse

...
module:{
  noParse:[/react\.production\.min\.js/]
}
...

DLL 动态链接库

区分正式测试环境

cdn设置

  1. HTML文件不缓存,放在自己的服务器上,关闭自己服务器的缓存,静态资源的URL变成指向CDN服务器的地址
  2. 静态的JavaScript、CSS、图片等文件开启CDN和缓存,并且文件名带上HASH值
  3. 为了并行加载不阻塞,把不同的静态资源分配到不同的CDN服务器上
output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name]_[hash:8].js',
   publicPath: 'http://baidu.com'//生成的静态资源的前缀
}

package.json设置脚本运行的环境变量

  1. window系统设置是通过
"test": "set NDOE_ENV=development && webpack --mode development"
  1. mac系统设置是通过
"test": "export NDOE_ENV=development && webpack --mode development"

3.如果统一的话 安装包cnpm install cross-env -D 并且通过以下方式设置环境变量

"test": "crocess_env NDOE_ENV=development && webpack --mode development"

ps: 以上设置的环境变量在webpack的配置文件中是可以直接通过process.env.NODE_ENV来获取到的

源代码中区分测试还是正式环境

...
plugins:[
  new webpack.DefinePlugin({
      'process.env':{
           NODE_ENV: JSON.stringify(process.env.NODE_ENV),
           PRODUCT_NAEM: JSON.stringify(process.env.PRODUCT_NAME)
       }
  })
]
...
if(process.env.NODE_ENV === 'development') {
}

模块热替换

  1. 模块热替换(hot module replacement)的技术可以在不刷新整个网页的情况下只更新指定的模块,原理是当一个源码发生变化时,只重新编译发生变化的模块,再用新输出的模块替换掉浏览器中老的模块
  2. 编译更快,需要的时间更短
  3. 不刷新网页可以保留网页运行状态
  4. webpack.config.js配置
const webpack = require('webpack')
...
devServer: {
    hot: true
}
plugins:[
  ...
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NamedModulesPlugin()
]
  1. 源码中使用方式
if(module.hot) {
    //如果检测到了base更新了,则执行这个函数
    module.hot.accept('./base', function() { //如果这个文件发生变化了,则执行这个函数,不会刷新页面了

        
    }) 
}

Tree Shaking

ps: 可以剔除js中不用的代码;依赖静态的es6模块化语法,比如通过import 和export 导入导出

//info.js
export function getName() {

    return 'tree-shaking'
}

export function getAge() {

    return '2.0'
}
//index.js
import { getName } from './info.js'

let name = getName;

console.log(name);
//main.b78eb869.js 打包之后的代码
(function(module, exports, __webpack_require__) {

"use strict";
eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n    value: true\n});\nexports.getName = getName;\nexports.getAge = getAge;\n\nfunction getName() {\n    return 'tree-shaking';\n}\n\nfunction getAge() {\n    return '2.0';\n}\n\n//# sourceURL=webpack:///./src1/info.js?");

/***/

ps: index.js并没有使用getAge方法,但是在打包之后的代码里面还是有getAge这个方法的

module:{
        rules:[
            {
                test: /\.js$/,
                use:{
                    loader:'babel-loader',
                    options:{

                        presets:[
                            //env模块编译es6语法,但是不编译module语法
                            ["env", {modules:false}]//含义是关闭 Babel 的模块转换功能,保留原本的 ES6 模块化语法
                        ]
                    }
                },
                include:path.resolve('./src'),//转义该目录下的文件
                exclude:/node_modules/ //该目录下的文件转成es5
            }
        ]
   },
  1. 再次编译,会发现getName已经不见了

提取公共代码

  1. 相同的资源被重复的加载,浪费用户的流量和服务器的成本;
  2. 每个页面需要加载的资源太大,导致网页首屏加载缓慢,影响用户体验。如果能把公共代码抽离成单独文件进行加载能进行优化,可以减少网络传输流量,降低服务器成本
  1. 基础类库,长期缓存
  2. 页面之间的公用代码
  3. 各个页面单独生成文件

es6 里面class属性的转换

  1. 安装插件
npm install --save-dev babel-plugin-transform-class-properties

2.配置.babelrc

// without options
{
  "plugins": ["transform-class-properties"]
}

// with options
{
  "plugins": [
    ["transform-class-properties", { "spec": true }]
  ]
}

webpack概念

上一篇 下一篇

猜你喜欢

热点阅读