Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webpack与gulp #11

Open
HolyZheng opened this issue Jun 24, 2018 · 2 comments
Open

webpack与gulp #11

HolyZheng opened this issue Jun 24, 2018 · 2 comments

Comments

@HolyZheng
Copy link
Owner

HolyZheng commented Jun 24, 2018

gulp

是什么

gulp是一个自动化构建工具,用来优化前端工作流程,可以帮助我们进行代码编译,压缩,图片压缩,资源合并等工作。

webpack

是什么

webpack是一个模块化资源打包工具,它支持多种模块化的方案,当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。并且通过对应的 loader ,我们还可以处理其他类型的文件,比如css,image。通过plugins还可以对代码进行压缩等操作。

ps:loader 类似于其他构建工具中“任务(task)”,用于对模块的源代码进行转换,可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL等等。

使用场景

用途就决定了它的使用场景,当我们想简化工作流程,自动化代码的压缩,编译,图片压缩,资源合并等操作,gulp可以排上用场。
如果是进行模块化开发,并根据模块依赖关系打包代码和资源的话,webpack可以排上用场,并且webpack通过plugins还可以做额外的事情。

@HolyZheng HolyZheng changed the title webpack与gulp webpack与gulp(待填坑) Jul 3, 2018
@HolyZheng
Copy link
Owner Author

HolyZheng commented Jul 3, 2018

webpack4总结

接触的时候已经到了webpack4版本。webpack4的改变:参考dwqs同学的webpack4不完全指南

关键概念

webpack中的关键概念

  • entry,webpack 应该使用哪个模块,来作为构建其内部依赖图的开始
  • output,告诉 webpack 在哪里输出它所创建的 bundles
  • loader,将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理
  • plugins,插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。
  • mode,值为development 或 production
/** webpack.production.config.js **/
   // webpack 2/3 
   module.exports = {
       plugins: [
        new UglifyJsPlugin(/* ... */),
        new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
        new webpack.optimize.ModuleConcatenationPlugin(),
/*
* 分析出模块之间的依赖关系,尽可能的把打散的模块合并到一个函数中去,但前提是不能造成代码冗
* 余。 因此只有那些被引用了一次的模块才能被合并。
*/
        new webpack.NoEmitOnErrorsPlugin()
// 在编译出现错误时,使用它来跳过输出阶段。这样可以确保输出资源不会包含错误。
       ]
     }
     
   // webpack 4  
   module.exports = {
   	mode: 'production'
   }
   /** webpack.development.config.js **/
   // webpack 2/3 
   module.exports = {
       plugins: [
        new webpack.NamedModulesPlugin(), 
// 当开启 HMR 的时候使用该插件会显示模块的相对路径,建议用于开发环境
        new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") })
       ]
     }
     
   // webpack 4  
   module.exports = {
   	mode: 'development'
   }

webpack4优化点

1.模块热替换

允许在运行时更新各种模块,而无需进行完全刷新。

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 每次打包创建新的html
const CleanWebpackPlugin = require('clean-webpack-plugin')
// 每次打包先清空dist文件夹
const webpack = require('webpack')

module.exports = {
  entry: {
    app: './src/index.js'
  },
  // 追踪错误,仅在开发阶段使用
  devtool: 'inline-source-map',
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'Development'
    }),
    // new webpack.NamedModulesPlugin(), 生成环境下默认开启
    // 以便更容易查看要修补(patch)的依赖
    new webpack.HotModuleReplacementPlugin()
    // 热替换模块
  ],
  mode: 'development',
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
// 将dist目录下的文件作为可访问文件,在package.json中添加script脚本
// "start": "webpack-dev-server --open"
  devServer: {
    contentBase: './dist',
    hot: true
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
        // style-loader当更新 CSS 依赖模块时,此 loader 在后台使用 module.hot.accept 来修补(patch) 
        // <style> 标签
      }
    ]
  }
}

2.tree shaking

tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import 和 export。我们需要做的就是将文件标记为无副作用,或者将有副作用的文件标记出来。

  • 在package.json中配置
{
  "name": "your-project",
  "sideEffects": false
// 都没有副作用,都可以进行tree shaking
}

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js",
    "*.css"
  ]
// 列出有副作用的文件,避免进行tree shaking
}

ps:副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。

3. 生成环境搭建

针对不同的环境,进行不同的配置,用webpage-merge进行合并。
如:

// webpack.common.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = {
  entry: {
    app: './src/index.js'
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'production'
    })
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
}
// webpack.dev.js

const merge = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
  devtool: 'inline-source-map',
  devServer: {
    contentBase: './dist'
  }
})
// webpack.prod.js

const merge = require('webpack-merge')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const common = require('./webpack.common.js')
const webpack = require('webpack')

module.exports = merge(common, {
  devtool: 'source-map',
  plugins: [
    // new UglifyJSPlugin({
    // sourceMap: true
    //}),
    // 在webpack4的production模式下,webpack.DefinePlugin 插件的 
    // process.env.NODE_ENV 的值不需要再定义,默认是 production
    // new webpack.DefinePlugin({
     //  'process.env.NODE_ENV': JSON.stringify('production')
    // })
    // webpack中需要通过defineplugin来设置process.env.NODE_ENV的值,
    // 以便其他的library使用该变量
  ],
  mode: 'production'
})

4.公共代码提取,常用代码提取,webpack的runtime代码提取

参考文章:RIP CommonsChunkPlugin
推荐参考翻译:RIP CommonsChunkPlugin翻译
webpack4移除了CommonsChunkPlugin插件,增加了optimization.splitchunksoptimization.runtimeChunk配置项,这两个配置项的默认配置已经可以满足大部分用户的需求。

“async initial all”的区别

// 默认配置
splitChunks: {
	chunks: "async",
	minSize: 30000,
	minChunks: 1,
	maxAsyncRequests: 5,
	maxInitialRequests: 3,
	name: true,
	cacheGroups: {
		default: {
			minChunks: 2,
			priority: -20,
			reuseExistingChunk: true,
		},
		vendors: {
			test: /[\\/]node_modules[\\/]/,
			priority: -10
		}
	}
}

weback3的配置

new webpack.optimize.CommonsChunkPlugin({
      name: "common",
      minChunks: 2,
      minSize: 30000
})

new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: module => {
    return module.resource && /node_modules/.test(module.resource)
  }
}),
//  webpack 自身的这部分代码分离出来
new webpack.optimize.CommonsChunkPlugin({
      name: "runtime",
      minChunks: Infinity
})

5.懒加载

6.缓存

为了避免由于文件名字没有改变,浏览器误以为我们文件的内容没有改变,直接使用内存中的缓存,而造成不必要的后果,配置chunkhash

output: {
    filename: '[name].[chunkhash].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }

使得每次修改都会产生一个唯一的hash后缀,以区别文件名,使得浏览器可以使用到最新版本的代码。
wbepack4之前,会因为webpack自身的样板和mainifest,会造成即使没有修改代码,但是再次打包出来的代码名称中的hash却改变的问题,需要通过插件来提取出来。

// webpack4中取消了该插件
new webpack.optimize.CommonsChunkPlugin({
      name: "runtime",
      minChunks: Infinity
})
// webpack4
optimization.runtimeChunk: true

vue环境配置

用到vue-loadervue-style-loader

module: {
    // .vue文件中使用css需要css-loader
    // vue-style-loader是vue-loader的dependencies
    // css-loader 是 vue-loader的peerDependencies
    rules: [
     {
        test: /\.js$/,
        use: 'babel-loader',
        include: [path.resolve(__dirname, '../src')]
      },
      {
        test: /\.vue$/,
        use: ['vue-loader']
      },
      {
        test: /\.css$/,
        use: ['vue-style-loader', 'css-loader']
      },
      {
        test: /\.s[ac]ss$/,
        use: ['vue-style-loader', 'css-loader', 'sass-loader']
      }
    ]
  }

@HolyZheng
Copy link
Owner Author

HolyZheng commented Jul 16, 2018

gulp

gulp的配置文件为 gulpfile.js 其中有几个关键和 api 的概念:

Task任务

gulp的配置可以说是由一个个的任务组成,每个任务都由一个名字(自定义或者default),可以通过命令指定要执行的任务。

// 执行default任务
gulp 
// 执行特点任务
gulp name

插件

任务的完成通常需要插件的帮助,常用插件有:

  • gulp-connect:创建本地服务器;
  • gulp-minify-css:压缩css;
  • gulp-uglify:压缩js;
  • gulp-imagemin:压缩图片;
  • gulp-clean:删除文件用的;
  • gulp-rename:重命名文件;
  • gulp-minify-html:压缩html用的;
  • gulp-inject:将css样式和js脚本文件插入到html文件中;
  • gulp-postcss:自动添加css中的前缀

常用Api

  • gulp.task:定义一个任务;
  • gulp.src:匹配文件;
  • gulp.dest:输出文件到指定目录;
  • gulp.watch:监听文件,触发相应的任务
    一个例子:
gulp.task('script', function () {
    gulp.src('./src/**/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('dist'))
});

gulp.task('default', ['script'], function () {
    gulp.watch('./src/js/*.js', ['script']);
});

执行顺序

gulp中的任务,在默认情况下,会·已最大的并发数同时运行,也就是说,它会不做任何等待地将所有的任务同时开起来。如果你希望创建一个有特定顺序的串行的任务链,你需要做两件事:

  1. 给它一个提示,用以告知任务在什么时候完成,
  2. 而后,再给一个提示,用以告知某任务需要依赖另一个任务的完成。
    官方两个例子:
var gulp = require('gulp');

// 传入一个回调函数,因此引擎可以知道何时它会被完成
gulp.task('one', function(cb) {
    // 做一些事 -- 异步的或者其他任何的事
    cb(err); // 如果 err 不是 null 和 undefined,流程会被结束掉,'two' 不会被执行
});

// 标注一个依赖,依赖的任务必须在这个任务开始之前被完成
gulp.task('two', ['one'], function() {
    // 现在任务 'one' 已经完成了
});

gulp.task('default', ['one', 'two']);
// 也可以这么写:gulp.task('default', ['two']);
var gulp = require('gulp');
var del = require('del'); // rm -rf

gulp.task('clean', function(cb) {
    del(['output'], cb);
});

gulp.task('templates', ['clean'], function() {
    var stream = gulp.src(['src/templates/*.hbs'])
        // 执行拼接,压缩,等。
        .pipe(gulp.dest('output/templates/'));
    return stream; // 返回一个 stream 来表示它已经被完成

});

gulp.task('styles', ['clean'], function() {
    var stream = gulp.src(['src/styles/app.less'])
        // 执行一些代码检查,压缩,等
        .pipe(gulp.dest('output/css/app.css'));
    return stream;
});

gulp.task('build', ['templates', 'styles']);

// templates 和 styles 将会并行处理
// clean 将会保证在任一个任务开始之前完成
// clean 并不会被执行两次,尽管它被作为依赖调用了两次

gulp.task('default', ['build']);

@HolyZheng HolyZheng changed the title webpack与gulp(待填坑) webpack与gulp Jul 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant