一小时学会前端工程化

1、概要

1.一、前端工程化

随着前端的不断发展与壮大,前端变得愈来愈复杂,组件化、模块化、工程化、自动化成了前端发展中不可或缺的一部分,具体到前端工程化,面临的问题是如何提升编码->测试->维护阶段的生产效率。css

前端工程化是使用软件工程的技术和方法来进行前端项目的开发、维护和管理。html

前端工程化是依据业务特色,将前端开发的规范、流程、技术、工具、经验等造成规范并创建成一种标准的体系。前端

如今的项目可能会不停的迭代,发布就成了平常开发的一部分,前端不只要保证功能还要保证性能,传统的一次次的发布效率会很是低,前端工程化通常都有会借助一些工具。vue

实现前端工程化的目的简单来讲就是经过流程规范、自动化工具来提高前端的开发效率、性能、质量、多人协做能力以及开发体验,创建前端工程化是各个团队必经的成长过程。node

1.1.一、前端工程化的任务

前端不只要保证功能还要考虑性能,要减小http请求数量、压缩、合并、预处理、规范代码、清理、打包、转换等工做。react

前端大部分状况下源代码没法直接运行,必须经过转换后才能够正常运行。构建就是作这件事情,把源代码转换成发布到线上的可执行 JavaScrip、CSS、HTML 代码,包括以下内容。jquery

(1)、代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等。webpack

(2)、文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等。git

(3)、代码分割:提取多个页面的公共代码、提取首屏不须要执行部分的代码让其异步加载。github

(4)、模块合并:在采用模块化的项目里会有不少个模块和文件,须要构建功能把模块分类合并成一个文件。

(5)、自动刷新:监听本地源代码的变化,自动从新构建、刷新浏览器。

(6)、代码校验:在代码被提交到仓库前须要校验代码是否符合规范,以及单元测试是否经过。

(7)、自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。

构建实际上是工程化、自动化思想在前端开发中的体现,把一系列流程用代码去实现,让代码自动化地执行这一系列复杂的流程。 构建给前端开发注入了更大的活力,解放了咱们的生产力。

1.二、前端工程化工具

历史上前后出现一系列构建工具,它们各有其优缺点。因为前端工程师很熟悉 JavaScript ,Node.js 又能够胜任全部构建需求,因此大多数构建工具都是用 Node.js 开发的。

构建工具的主要功能就是实现自动化处理,例如对代码进行检查、预编译、合并、压缩;生成雪碧图、sourceMap、版本管理;运行单元测试、监控等,固然有的工具还提供模块化、组件化的开发流程功能。

 

若是把工具按类型分能够分为这三类:

(一)、基于任务运行的工具:Grunt、Gulp

它们会自动执行指定的任务,就像流水线,把资源放上去而后经过不一样插件进行加工,它们包含活跃的社区,丰富的插件,能方便的打造各类工做流。

(二)、基于模块化打包的工具:Browserify、Webpack、rollup.js

有过 Node.js 开发经历的应该对模块很熟悉,须要引用组件直接一个 require 就 OK,这类工具就是这个模式,还能够实现按需加载、异步加载模块。

(三)、整合型工具:Yeoman、FIS、jdf、Athena、cooking、weflow

使用了多种技术栈实现的脚手架工具,好处是即开即用,缺点就是它们约束了技术选型,而且学习成本相对较高。

1.2.一、Grunt

Grunt([ɡrʌnt]做呼噜声) 生态系统很是庞大,而且一直在增加。因为拥有数量庞大的插件可供选择,所以,你能够利用 Grunt 自动完成许多事,而且花费不多的代价。若是找不到你所须要的插件,那就本身动手创造一个 Grunt 插件,而后将其发布到 npm 上吧。

官网:https://gruntjs.com/

GitHub:https://github.com/gruntjs/

中文网:https://www.gruntjs.net/

对于须要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,自动化工具能够减轻你的劳动,简化你的工做。当你在 Gruntfile 文件正确配置好了任务,任务运行器就会自动帮你或你的小组完成大部分无聊的工做。

Grunt 是老牌的构建工具,特色是配置驱动,你须要作的就是了解各类插件的功能,而后把配置整合到 Gruntfile.js 中,下面是配置例子:

复制代码
module.exports = function(grunt) {
    grunt.initConfig({
        jshint: {
            files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
            options: {
                globals: {
                    jQuery: true
                }
            }
        },
        watch: {
            files: ['<%= jshint.files %>'],
            tasks: ['jshint']
        }
    });

    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');

    grunt.registerTask('default', ['jshint']);
};
复制代码

Grunt 缺点也是配置驱动,当任务很是多的状况下,试图用配置完成全部事简直就是个灾难;再就是它的 I/O 操做也是个弊病,它的每一次任务都须要从磁盘中读取文件,处理完后再写入到磁盘,例如:我想对多个 less 进行预编译、压缩操做,那么 Grunt 的操做就是:

读取 less 文件 -> 编译成 css -> 存储到磁盘 -> 读取 css -> 压缩处理 -> 存储到磁盘

这样一来当资源文件较多,任务较复杂的时候性能就是个问题了。

1.2.二、Gulp

Gulp(ɡʌlp狼吞虎咽地吃,吞咽)是一个基于流的自动化构建工具。 除了能够管理和执行任务,还支持监听文件、读写文件。

中文网:https://www.gulpjs.com.cn/

官网:https://gulpjs.com/

特色:

易于使用:经过代码优于配置的策略,Gulp 让简单的任务简单,复杂的任务可管理。

构建快速:利用 Node.js 流的威力,你能够快速构建项目并减小频繁的 IO 操做。

插件高质:Gulp 严格的插件指南确保插件如你指望的那样简洁高质得工做。

易于学习:经过最少的 API,掌握 Gulp 不太费力,构建工做尽在掌握:如同一系列流管道。

Gulp 被设计得很是简单,只经过下面5种个方法就能够胜任几乎全部构建场景:

经过 gulp.task 注册一个任务;

经过 gulp.run 执行任务;

经过 gulp.watch 监听文件变化;

经过 gulp.src 读取文件;

经过 gulp.dest 写文件。

Gulp 的最大特色是引入了流的概念,同时提供了一系列经常使用的插件去处理流,流能够在插件之间传递

Gulp 特色是代码驱动,写任务就和写普通的 Node.js 代码同样:

复制代码
var gulp = require('gulp');
var pug = require('gulp-pug');
var less = require('gulp-less');
var minifyCSS = require('gulp-csso');

gulp.task('html', function(){
    return gulp.src('client/templates/*.pug')
        .pipe(pug())
        .pipe(gulp.dest('build/html'))
});

gulp.task('css', function(){
    return gulp.src('client/templates/*.less')
        .pipe(less())
        .pipe(minifyCSS())
        .pipe(gulp.dest('build/css'))
});

gulp.task('default', [ 'html', 'css' ]);
复制代码

再一个对文件读取是流式操做(Stream),也就是说一次 I/O 能够处理多个任务,仍是 less 的例子,Gulp 的流程就是:

读取 less 文件 -> 编译成 css -> 压缩处理 -> 存储到磁盘

Gulp 做为任务类型的工具没有明显的缺点,惟一的问题可能就是完成相同的任务它须要写的代码更多一些,因此除非是项目有历史包袱(原有项目就是基于 Grunt 构建)在 Grunt 与 Gulp 对比看来仍是比较推荐 Gulp!

适用场景:

经过上面的介绍能够看出它们侧重对整个过程的控制管理,实现简单、对架构无要求、不改变开发模式,因此很是适合前端、小型、须要快速启动的项目。

1.2.三、Yeoman

Yeoman([ˈjoʊmən]自耕农,自由民; 义勇骑兵队成员,young+man)的目的不只是要为新项目创建工做流,同时仍是为了解决前端开发所面临的诸多严重问题,例如零散的依赖关系。
Yeoman是Google的团队和外部贡献者团队合做开发的,他的目标是经过Grunt(一个用于开发任务自动化的命令行工具)和Bower(一个HTML、CSS、Javascript和图片等前端资源的包管理器)的包装为开发者建立一个易用的工做流。

Yeoman是一个强健的脚手架与构建工具,库,及工做流程的组合,帮你网页开发者快速建立出漂亮并且引人入胜的网页程序,Yeoman帮助咱们建立项目,提供更好的工具来使咱们的项目更多样化。

Yeoman提供generator系统,一个generator是一个插件,在咱们在一个完整的项目上使用‘yo’命令时,会运行该generator。经过这些官方的Generators,推出了Yeoman工做流,工做流是一个健壮、有本身特点的客户端堆栈,包含能快速构建漂亮的网络应用的工具和框架。Yeoman提供了负责开始项目开发的一切,没有任何让人头痛的手动配置。

Yeoman主要提供了三个工具:脚手架(yo),构建工具(grunt),包管理器(bower)。这三个工具是分别独立开发的,可是须要配合使用,来实现咱们更高效的工做流模式。

小结:

在 Npm Script 和 Grunt 时代,Web 开发要作的事情变多,流程复杂,自动化思想被引入,用于简化流程;

在 Gulp 时代开始出现一些新语言用于提升开发效率,流式处理思想的出现是为了简化文件转换的流程,例如将 ES6 转换成 ES5。

在 Webpack 时代因为单页应用的流行,一个网页的功能和实现代码变得庞大,Web 开发向模块化改进。

这些构建工具都有各自的定位和专一点,它们之间既能够单独地完成任务,也能够相互搭配起来弥补各自的不足。 在了解这些常见的构建工具后,你须要根据本身的需求去判断应该如何选择和搭配它们才能更好地完成本身的需求。

通过多年的发展, Webpack 已经成为构建工具中的首选,缘由是:

大多数团队在开发新项目时会采用紧跟时代的技术,这些技术几乎都会采用“模块化+新语言+新框架”,Webpack 能够为这些新项目提供一站式的解决方案;

Webpack 有良好的生态链和维护团队,能提供良好的开发体验和保证质量;

Webpack 被全世界的大量 Web 开发者使用和验证,能找到各个层面所需的教程和经验分享。

1.三、WebPack

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序须要的每一个模块,而后将全部这些模块打包成一个或多个 bundle。

Webpack 是一个打包模块化 JavaScript 的工具,在 Webpack 里一切文件皆模块,经过 Loader 转换文件,经过 Plugin 注入钩子,最后输出由多个模块组合成的文件。Webpack 专一于构建模块化项目。

其官网的首页图很形象的画出了 Webpack 是什么,以下:

一切文件:JavaScript、CSS、SCSS、图片、模板,在 Webpack 眼中都是一个个模块,这样的好处是能清晰的描述出各个模块之间的依赖关系,以方便 Webpack 对模块进行组合和打包。 通过 Webpack 的处理,最终会输出浏览器能使用的静态资源。

Webpack 具备很大的灵活性,能配置如何处理文件,大体使用以下:

复制代码
module.exports = {
// 全部模块的入口,Webpack 从入口开始递归解析出全部依赖的模块
    entry: './app.js',
    output: {
// 把入口所依赖的全部模块打包成一个文件 bundle.js 输出 
        filename: 'bundle.js'
    }
}
复制代码

1.3.一、Webpack的特色

把一切都视为模块:无论是 CSS、JS、Image 仍是 HTML 均可以互相引用,经过定义 entry.js,对全部依赖的文件进行跟踪,将各个模块经过 loader 和 plugins 处理,而后打包在一块儿。

按需加载:打包过程当中 Webpack 经过 Code Splitting 功能将文件分为多个 chunks,还能够将重复的部分单独提取出来做为 commonChunk,从而实现按需加载。

优势:

专一于处理模块化的项目,能作到开箱即用一步到位;

经过 Plugin 扩展,完整好用又不失灵活;

使用场景不只限于 Web 开发;

社区庞大活跃,常常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展;

良好的开发体验。

缺点:

Webpack的缺点是只能用于采用模块化开发的项目。

上手比较难、对于新手而言须要经历踩坑的过程。

对于Server 端渲染的多页应用有点力不从心。

小结:

Webpack 特别适合配合 React.js、Vue.js 构建单页面应用以及须要多人合做的大型项目,在规范流程都已约定好的状况下每每能极大的提高开发效率与开发体验。

1.3.二、资源

官网:https://webpack.js.org/

github:https://github.com/webpack/webpack

中文网:https://www.webpackjs.com/

深刻浅出webpack电子书:http://webpack.wuhaolin.cn/

1.3.三、工做流程

Webpack 是经过配置来实现管理,与 Grunt 不一样的是它包含的许多自动化的黑盒操做因此配置起来会简单不少(但遇到问题调试起来就很麻烦),一个典型的配置以下:

复制代码
module.exports = {
    //插件项
    plugins: [commonsPlugin],
    //页面入口文件配置
    entry: {
        index : './src/js/page/index.js'
    },
    //入口文件输出配置
    output: {
        path: 'dist/js/page',
        filename: '[name].js'
    },
    module: {
        //加载器配置
        loaders: [
            { test: /\.css$/, loader: 'style-loader!css-loader' },
            { test: /\.js$/, loader: 'jsx-loader?harmony' },
            { test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
            { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}
        ]
    },
    //其它解决方案配置
    resolve: {
        root: '/Users/Bell/github/flux-example/src', //绝对路径
        extensions: ['', '.js', '.json', '.scss'],
        alias: {
            AppStore : 'js/stores/AppStores.js',
            ActionType : 'js/actions/ActionType.js',
            AppAction : 'js/actions/AppAction.js'
        }
    }
};
复制代码

 

1.3.四、搭建WebPack开发环境

(1)、安装NodeJS

在用 Webpack 执行构建任务时须要经过 webpack 可执行文件去启动构建任务,因此须要安装 webpack 可执行文件。 在安装 Webpack 前请确保你的系统安装了5.0.0及以上版本的 Node.js。

https://nodejs.org/下载安装

设置国内npm的镜像

$ npm install -g cnpm --registry=https://registry.npm.taobao.org

使用时用cnpm代替npm

(2)、安装webpack

安装 Webpack 到全局

安装到全局后你能够在任何地方共用一个 Webpack 可执行文件,而不用各个项目重复安装,安装方式以下:

npm i -g webpack

cli:

全部cli参数:

webpack-cli 3.1.2

Usage: webpack-cli [options]
       webpack-cli [options] --entry <entry> --output <output>
       webpack-cli [options] <entries...> --output <output>
       webpack-cli <command> [options]

For more information, see https://webpack.js.org/api/cli/.

Config options:
  --config               Path to the config file
                         [string] [default: webpack.config.js or webpackfile.js]
  --config-register, -r  Preload one or more modules before loading the webpack
                         configuration      [array] [default: module id or path]
  --config-name          Name of the config to use                      [string]
  --env                  Environment passed to the config, when it is a function
  --mode                 Enable production optimizations or development hints.
                                  [choices: "development", "production", "none"]

Basic options:
  --context    The base directory (absolute path!) for resolving the `entry`
               option. If `output.pathinfo` is set, the included pathinfo is
               shortened to this directory.
                                       [string] [default: The current directory]
  --entry      The entry point(s) of the compilation.                   [string]
  --watch, -w  Enter watch mode, which rebuilds on file change.        [boolean]
  --debug      Switch loaders to debug mode                            [boolean]
  --devtool    A developer tool to enhance debugging.                   [string]
  -d           shortcut for --debug --devtool eval-cheap-module-source-map
               --output-pathinfo                                       [boolean]
  -p           shortcut for --optimize-minimize --define
               process.env.NODE_ENV="production"                       [boolean]
  --progress   Print compilation progress in percentage                [boolean]

Module options:
  --module-bind       Bind an extension to a loader                     [string]
  --module-bind-post  Bind an extension to a post loader                [string]
  --module-bind-pre   Bind an extension to a pre loader                 [string]

Output options:
  --output, -o                  The output path and file for compilation assets
  --output-path                 The output directory as **absolute path**
                                (required).
                                       [string] [default: The current directory]
  --output-filename             Specifies the name of each output file on disk.
                                You must **not** specify an absolute path here!
                                The `output.path` option determines the location
                                on disk the files are written to, filename is
                                used solely for naming the individual files.
                                                   [string] [default: [name].js]
  --output-chunk-filename       The filename of non-entry chunks as relative
                                path inside the `output.path` directory.
       [string] [default: filename with [id] instead of [name] or [id] prefixed]
  --output-source-map-filename  The filename of the SourceMaps for the
                                JavaScript files. They are inside the
                                `output.path` directory.                [string]
  --output-public-path          The `publicPath` specifies the public URL
                                address of the output files when referenced in a
                                browser.                                [string]
  --output-jsonp-function       The JSONP function used by webpack for async
                                loading of chunks.                      [string]
  --output-pathinfo             Include comments with information about the
                                modules.                               [boolean]
  --output-library              Expose the exports of the entry point as library
                                                                        [string]
  --output-library-target       Type of library
         [string] [choices: "var", "assign", "this", "window", "self", "global",
      "commonjs", "commonjs2", "commonjs-module", "amd", "umd", "umd2", "jsonp"]

Advanced options:
  --records-input-path       Store compiler state to a json file.       [string]
  --records-output-path      Load compiler state from a json file.      [string]
  --records-path             Store/Load compiler state from/to a json file. This
                             will result in persistent ids of modules and
                             chunks. An absolute path is expected. `recordsPath`
                             is used for `recordsInputPath` and
                             `recordsOutputPath` if they left undefined.[string]
  --define                   Define any free var in the bundle          [string]
  --target                   Environment to build for                   [string]
  --cache                    Cache generated modules and chunks to improve
                             performance for multiple incremental builds.
                      [boolean] [default: It's enabled by default when watching]
  --watch-stdin, --stdin     Stop watching when stdin stream has ended [boolean]
  --watch-aggregate-timeout  Delay the rebuilt after the first change. Value is
                             a time in ms.                              [number]
  --watch-poll               Enable polling mode for watching           [string]
  --hot                      Enables Hot Module Replacement            [boolean]
  --prefetch                 Prefetch this request (Example: --prefetch
                             ./file.js)                                 [string]
  --provide                  Provide these modules as free vars in all modules
                             (Example: --provide jQuery=jquery)         [string]
  --labeled-modules          Enables labeled modules                   [boolean]
  --plugin                   Load this plugin                           [string]
  --bail                     Report the first error as a hard error instead of
                             tolerating it.            [boolean] [default: null]
  --profile                  Capture timing information for each module.
                                                       [boolean] [default: null]

Resolving options:
  --resolve-alias         Redirect module requests                      [string]
  --resolve-extensions    Redirect module requests                       [array]
  --resolve-loader-alias  Setup a loader alias for resolving            [string]

Optimizing options:
  --optimize-max-chunks      Try to keep the chunk count below a limit
  --optimize-min-chunk-size  Minimal size for the created chunk
  --optimize-minimize        Enable minimizing the output. Uses
                             optimization.minimizer.                   [boolean]

Stats options:
  --color, --colors               Enables/Disables colors on the console
                                           [boolean] [default: (supports-color)]
  --sort-modules-by               Sorts the modules list by property in module
                                                                        [string]
  --sort-chunks-by                Sorts the chunks list by property in chunk
                                                                        [string]
  --sort-assets-by                Sorts the assets list by property in asset
                                                                        [string]
  --hide-modules                  Hides info about modules             [boolean]
  --display-exclude               Exclude modules in the output         [string]
  --display-modules               Display even excluded modules in the output
                                                                       [boolean]
  --display-max-modules           Sets the maximum number of visible modules in
                                  output                                [number]
  --display-chunks                Display chunks in the output         [boolean]
  --display-entrypoints           Display entry points in the output   [boolean]
  --display-origins               Display origins of chunks in the output
                                                                       [boolean]
  --display-cached                Display also cached modules in the output
                                                                       [boolean]
  --display-cached-assets         Display also cached assets in the output
                                                                       [boolean]
  --display-reasons               Display reasons about module inclusion in the
                                  output                               [boolean]
  --display-depth                 Display distance from entry point for each
                                  module                               [boolean]
  --display-used-exports          Display information about used exports in
                                  modules (Tree Shaking)               [boolean]
  --display-provided-exports      Display information about exports provided
                                  from modules                         [boolean]
  --display-optimization-bailout  Display information about why optimization
                                  bailed out for modules               [boolean]
  --display-error-details         Display details about errors         [boolean]
  --display                       Select display preset
              [string] [choices: "", "verbose", "detailed", "normal", "minimal",
                                                          "errors-only", "none"]
  --verbose                       Show more details                    [boolean]
  --info-verbosity                Controls the output of lifecycle messaging
                                  e.g. Started watching files...
                 [string] [choices: "none", "info", "verbose"] [default: "info"]
  --build-delimiter               Display custom text after build output[string]

Options:
  --help, -h     Show help                                             [boolean]
  --version, -v  Show version number                                   [boolean]
  --silent       Prevent output from being displayed in stdout         [boolean]
  --json, -j     Prints the result as JSON.                            [boolean]
View Code

要安装 Webpack 到本项目,可按照你的须要选择如下任意命令运行:

复制代码
# npm i -D 是 npm install --save-dev 的简写,是指安装模块并保存到 package.json 的 devDependencies
# 安装最新稳定版
npm i -D webpack

# 安装指定版本
npm i -D webpack@<version>

# 安装最新体验版本
npm i -D webpack@beta
复制代码

2、快速上手

2.一、建立一个项目或目录

建立一个空项目或一个空目录,不必定须要使用IDE,这里我使用WebStorm

2.二、初始化项目

npm init -y (-y直接跳过提问阶段)

复制代码
name - 包名.
version - 包的版本号。
description - 包的描述。
homepage - 包的官网URL。
author - 包的做者,它的值是你在https://npmjs.org网站的有效帐户名,遵循“帐户名<邮件>”的规则,例如:zhangsan <zhangsan@163.com>。
contributors - 包的其余贡献者。
dependencies / devDependencies - 生产/开发环境依赖包列表。它们将会被安装在 node_module 目录下。
repository - 包代码的Repo信息,包括type和URL,type能够是git或svn,URL则是包的Repo地址。
main - main 字段指定了程序的主入口文件,require('moduleName') 就会加载这个文件。这个字段的默认值是模块根目录下面的 index.js。
keywords - 关键字
复制代码

package.json详解

2.三、安装webpack

webpack4须要安装webpack-cli:

npm i webpack webpack-cli --save-dev

2.四、建立目录与文件

src/bar.js

复制代码
//定义模块
//部分依赖lodash中的join方法
import {join} from 'lodash'

//导出一个默认模块
export default function bar() {
    function component() {
        //建立DOM元素
        var element=document.createElement("h2");
        //使用join链接数组将结果写入元素的html中
        element.innerHTML=join(['Hello','Webpack','!'],' ');
        return element;
    }
    //在body中添加子元素
    document.body.appendChild(component());
}
复制代码

实现使用lodash的join 链接字符串,在网页中输出字符串

依赖lodash、npm安装lodash,在bar.js中import lodash的join方法,输出text

npm i lodash --save

src/index.js

复制代码
//入口文件

//导入自定义好的模块
import bar from './bar';
//调用
bar();
复制代码

建立配置文件webpack.config.js

复制代码
//webpack配置文件

//依赖node中的path模块
const path=require('path');

//定义一个默认模块对象
module.exports={
    //指定入口文件的位置
    entry:"./src/index.js",
    //设置输出结果
    output: {
        //路径,将相对路径转绝对路径
        path:path.resolve(__dirname,'dist'),
        //文件
        filename: "bundle.js"
    }
};
复制代码

path.resolve获取文件的路径,_dirname为当前模块的绝对路径,详细解释以下:

path.resolve()
//做用:path.resolve() 该方法将一些的 路径/路径段 解析为绝对路径。
//语法:path.resolve( [from…],to )
//说明:将参数to位置的字符解析到一个绝对路径里,[from … ]为选填项,路径源;

用法:
var path = require("path")     //引入node的path模块

path.resolve('/foo/bar', './baz')   // returns '/foo/bar/baz'
path.resolve('/foo/bar', 'baz')   // returns '/foo/bar/baz'
path.resolve('/foo/bar', '/baz')   // returns '/baz'
path.resolve('/foo/bar', '../baz')   // returns '/foo/baz'
path.resolve('home','/foo/bar', '../baz')   // returns '/foo/baz'
path.resolve('home','./foo/bar', '../baz')   // returns '/home/foo/baz'
path.resolve('home','foo/bar', '../baz')   // returns '/home/foo/baz'
//总结:从后向前,若字符以 / 开头,不会拼接到前面的路径;若以 ../ 开头,拼接前面的路径,且不含最后一节路径;若以 ./ 开头 或者没有符号 则拼接前面路径;

//另:path.resolve老是返回一个以相对于当前的工做目录(working directory)的绝对路径。
View Code

index.html

webpack建立dist文件在dist中生成打包文件,而后再index.html中引用index.js文件

复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello WebPack</title>
</head>
<body>
<h2>Hello WebPack</h2>
<script src="dist/bundle.js"></script>
</body>
</html>
复制代码

2.五、使用webpack命令打包

能够指定配置文件

webpack --config webpack.config.js

也可使用默认的配置文件

webpack

打包的结果:

!function(n){var t={};function r(e){if(t[e])return t[e].exports;var u=t[e]={i:e,l:!1,exports:{}};return n[e].call(u.exports,u,u.exports,r),u.l=!0,u.exports}r.m=n,r.c=t,r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:e})},r.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},r.t=function(n,t){if(1&t&&(n=r(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var e=Object.create(null);if(r.r(e),Object.defineProperty(e,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var u in n)r.d(e,u,function(t){return n[t]}.bind(null,u));return e},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},r.p="",r(r.s=3)}([function(n,t,r){(function(n,e){var u;
View Code

 bundle.js文件:

2.六、运行

3、核心概念与执行过程

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序须要的每一个模块,而后将全部这些模块打包成一个或多个 bundle。

从 webpack v4.0.0 开始,能够不用引入一个配置文件。然而,webpack 仍然仍是高度可配置的。在开始前你须要先理解几个核心概念:

3.一、模块(Module)

在Webpack里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的Entry开始递归找出全部依赖的模块。

webpack把一切都视为模块,无论是 CSS、JS、Image 仍是 HTML 均可以互相引用。Node.js 从最一开始就支持模块化编程。然而,在 web,模块化的支持正缓慢到来。在 web 存在多种支持 JavaScript 模块化的工具,这些工具各有优点和限制。webpack 基于从这些系统得到的经验教训,并将模块的概念应用于项目中的任何文件。

什么是 webpack 模块

对比 Node.js 模块,webpack 模块可以以各类方式表达它们的依赖关系,几个例子以下:

  1. ES2015 import 语句
  2. CommonJS require() 语句
  3. AMD define 和 require 语句
  4. css/sass/less 文件中的 @import 语句。
  5. 样式(url(...))或 HTML 文件(<img src=...>)中的图片连接(image url)

支持的模块类型

webpack 经过 loader 能够支持各类语言和预处理器编写模块。loader 描述了 webpack 如何处理 非 JavaScript(non-JavaScript) _模块_,而且在 bundle 中引入这些依赖。 webpack 社区已经为各类流行语言和语言处理器构建了 loader,包括:

  1. CoffeeScript
  2. TypeScript
  3. ESNext (Babel)
  4. Sass
  5. Less
  6. Stylus

3.二、入口(entry)

入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。

入口起点(entry point)指示 webpack 应该使用哪一个模块,来做为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。

每一个依赖项随即被处理,最后输出到称之为 bundles 的文件中,咱们将在下一章节详细讨论这个过程。

能够经过在 webpack 配置中配置 entry 属性,来指定一个入口起点(或多个入口起点)。默认值为 ./src。

接下来咱们看一个 entry 配置的最简单例子:

复制代码
webpack.config.js

module.exports = {
    entry: './path/to/my/entry/file.js'
};
复制代码

根据应用程序的特定需求,能够以多种方式配置 entry 属性。

多入口与多出口:

复制代码
{
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
}

// 写入到硬盘:./dist/app.js, ./dist/search.js
复制代码

经常使用的占位:

  1. [hash]:模块标识符(module identifier)的 hash
  2. [chunkhash]:chunk 内容的 hash
  3. [name]:模块名称,key的名称,非文件名称
  4. [id]:模块标识符(module identifier)
  5. [query]:模块的 query,例如,文件名 ? 后面的字符串

3.三、出口(output)

输出结果,在 Webpack 通过一系列处理并得出最终想要的代码后输出结果。

output 属性告诉 webpack 在哪里输出它所建立的 bundles,以及如何命名这些文件,默认值为 ./dist。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你能够经过在配置中指定一个 output 字段,来配置这些处理过程:

复制代码
webpack.config.js

const path = require('path');

module.exports = {
    entry: './path/to/my/entry/file.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
    }
};
复制代码

在上面的示例中,咱们经过 output.filename 和 output.path 属性,来告诉 webpack bundle 的名称,以及咱们想要 bundle 生成(emit)到哪里。可能你想要了解在代码最上面导入的 path 模块是什么,它是一个 Node.js 核心模块,用于操做文件路径。

示例:

3.四、模块转换器(loader)

模块转换器,用于把模块原内容按照需求转换成新内容。

loader 让 webpack 可以去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 能够将全部类型的文件转换为 webpack 可以处理的有效模块,而后你就能够利用 webpack 的打包能力,对它们进行处理。

本质上,webpack loader 将全部类型的文件,转换为应用程序的依赖图(和最终的 bundle)能够直接引用的模块。

注意,loader 可以 import 导入任何类型的模块(例如 .css 文件),这是 webpack 特有的功能,其余打包程序或任务执行器的可能并不支持。咱们认为这种语言扩展是有很必要的,由于这可使开发人员建立出更准确的依赖关系图。

在更高层面,在 webpack 的配置中 loader 有两个目标:

  1. test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
  2. use 属性,表示进行转换时,应该使用哪一个 loader。
复制代码
webpack.config.js

const path = require('path');

const config = {
    output: {
        filename: 'my-first-webpack.bundle.js'
    },
    module: {
        rules: [
            { test: /\.txt$/, use: 'raw-loader' }
        ]
    }
};

module.exports = config;
复制代码

以上配置中,对一个单独的 module 对象定义了 rules 属性,里面包含两个必须属性:test 和 use。这告诉 webpack 编译器(compiler) 以下信息:

“webpack 编译器,当你碰到「在 require()/import 语句中被解析为 '.txt' 的路径」时,在你对它打包以前,先使用 raw-loader 转换一下。”

3.五、插件(plugins)

扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或作你想要的事情。

loader 被用于转换某些类型的模块,而插件则能够用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到从新定义环境中的变量。插件接口功能极其强大,能够用来处理各类各样的任务。

想要使用一个插件,你只须要 require() 它,而后把它添加到 plugins 数组中。多数插件能够经过选项(option)自定义。你也能够在一个配置文件中由于不一样目的而屡次使用同一个插件,这时须要经过使用 new 操做符来建立它的一个实例。

复制代码
webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 经过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件

const config = {
    module: {
        rules: [
            { test: /\.txt$/, use: 'raw-loader' }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({template: './src/index.html'})
    ]
};

module.exports = config;
复制代码

3.六、模式(mode)

经过选择 development 或 production 之中的一个,来设置 mode 参数,你能够启用相应模式下的 webpack 内置的优化

module.exports = {
    mode: 'production'
};

webpack4容许咱们指定编译使用开发模式仍是生产模式,这由mode这个配置来控制,value为枚举值:development/production,分别对应开发模式和生产模式(这个配置能够做为命令行的配置参数也能够做为配置文件中的一个配置项,默认值是production,即生产模式)。

源码仍是不支持调试(都用eval函数包住),指定编译时的source-map生成方式,默认值是eval,能够解决问题。

3.七、代码块(Chunk)

一个 Chunk 由多个模块组合而成,用于代码合并与分割。

3.八、WebPack执行过程

Webpack 启动后会从 Entry 里配置的 Module 开始递归解析 Entry 依赖的全部 Module。 每找到一个 Module, 就会根据配置的 Loader 去找出对应的转换规则,对 Module 进行转换后,再解析出当前 Module 依赖的 Module。 这些模块会以 Entry 为单位进行分组,一个 Entry 和其全部依赖的 Module 被分到一个组也就是一个 Chunk。最后 Webpack 会把全部 Chunk 转换成文件输出。 在整个流程中 Webpack 会在恰当的时机执行 Plugin 里定义的逻辑。

Webpack从入口(entry)开始工做,一般这些是JavaScript模块,其中webpack开始其遍历过程。在此过程当中,webpack会根据加载器配置评估入口(entry)匹配,这些配置告诉webpack如何转换每一个匹配。

入口(entry)自己就是一个模块。当webpack遇到一个入口时,webpack会尝试使用入口的resolve配置将入口与文件系统匹配。除了node_modules以外,咱们还能够告诉webpack对特定目录执行查找。也能够调整webpack与文件扩展名匹配的方式,而且能够为目录定义特定的别名。该耗竭与包章涵盖了更详细的这些想法。

若是解析经过失败,webpack会引起运行时错误。若是webpack设法正确解析文件,webpack将根据加载器定义对匹配的文件执行处理。每一个加载器对模块内容应用特定的转换。

能够经过多种方式配置加载程序与已解析文件匹配的方式,包括文件类型和文件系统中的位置。Webpack的灵活性甚至容许咱们根据文件导入项目的位置对文件应用特定的转换。

对webpack的加载器执行相同的解析过程。Webpack容许咱们在肯定应使用哪一个加载器时应用相似的逻辑。因为这个缘由,装载程序已经解析了本身的配置。若是webpack没法执行加载程序查找,则会引起运行时错误。

在实际应用中你可能会遇到各类奇怪复杂的场景,不知道从哪开始。 根据以上总结,你会对 Webpack 有一个总体的认识,这能让你在之后使用 Webpack 的过程当中快速知道应该经过配置什么去完成你想要的功能,而不是无从下手。

 下图能够简易的描述出webpack打包过程,该过程主要分为三个阶段:module构建、trunk构建和产出三个阶段:

4、模块转换器Loader

loader 用于对模块的源代码进行转换。loader 可使你在 import 或"加载"模块时预处理文件。所以,loader 相似于其余构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 能够将文件从不一样的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至容许你直接在 JavaScript 模块中 import CSS文件!

loader 是对应用程序中资源文件进行转换。它们是(运行在 Node.js 中的)函数,能够将资源文件做为参数的来源,而后返回新的资源文件。

 

4.一、loader特性

loader 支持链式传递。可以对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。

  • loader 能够是同步的,也能够是异步的。
  • loader 运行在 Node.js 中,而且可以执行任何可能的操做。
  • loader 接收查询参数。用于对 loader 传递配置。
  • loader 也可以使用 options 对象进行配置。

除了使用 package.json 常见的 main 属性,还能够将普通的 npm 模块导出为 loader,作法是在 package.json 里定义一个 loader 字段。

插件(plugin)能够为 loader 带来更多特性。

loader 可以产生额外的任意文件。

loader 经过(loader)预处理函数,为 JavaScript 生态系统提供了更多能力。 用户如今能够更加灵活地引入细粒度逻辑,例如压缩、打包、语言翻译和其余更多。

loader 遵循标准的模块解析。多数状况下,loader 将从模块路径(一般将模块路径认为是 npm install, node_modules)解析。

loader 模块须要导出为一个函数,而且使用 Node.js 兼容的 JavaScript 编写。一般使用 npm 进行管理,可是也能够将自定义 loader 做为应用程序中的文件。按照约定,loader 一般被命名为 xxx-loader(例如 json-loader)。

4.二、使用loader的三种方式

(1)、配置(推荐):在 webpack.config.js 文件中指定 loader

module.rules 容许你在 webpack 配置中指定多个 loader。 这是展现 loader 的一种简明方式,而且有助于使代码变得简洁。同时让你对各个 loader 有个全局概览:

复制代码
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          }
        ]
      }
    ]
  }
复制代码

Loaders须要单独安装而且须要在webpack.config.js中的modules关键字下进行配置,Loaders的配置包括如下几方面:

复制代码
test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)

loader:loader的名称(必须)

include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不须要处理的文件(文件夹)(可选)

query:为loaders提供额外的设置选项(可选)
复制代码

(2)、内联:在每一个 import 语句中显式指定 loader

能够在 import 语句或任何等效于 "import" 的方式中指定 loader。使用 ! 将资源中的 loader 分开。分开的每一个部分都相对于当前目录解析。

import Styles from 'style-loader!css-loader?modules!./styles.css';

经过前置全部规则及使用 !,能够对应覆盖到配置中的任意 loader。

选项能够传递查询参数,例如 ?key=value&foo=bar,或者一个 JSON 对象,例如 ?{"key":"value","foo":"bar"}。

尽量使用 module.rules,由于这样能够减小源码中的代码量,而且能够在出错时,更快地调试和定位 loader 中的问题。

(3)、CLI:在 shell 命令中指定它们

你也能够经过 CLI 使用 loader:

webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

这会对 .jade 文件使用 jade-loader,对 .css 文件使用 style-loader 和 css-loader。

4.三、常见的loader

4.3.一、文件

  • raw-loader 加载文件原始内容(utf-8)
  • val-loader 将代码做为模块执行,并将 exports 转为 JS 代码
  • url-loader 像 file loader 同样工做,但若是文件小于限制,能够返回 data URL
  • file-loader 将文件发送到输出文件夹,并返回(相对)URL

4.3.二、JSON

4.3.三、转换编译(Transpiling)

4.3.四、模板(Templating)

  • html-loader 导出 HTML 为字符串,须要引用静态资源
  • pug-loader 加载 Pug 模板并返回一个函数
  • jade-loader 加载 Jade 模板并返回一个函数
  • markdown-loader 将 Markdown 转译为 HTML
  • react-markdown-loader 使用 markdown-parse parser(解析器) 将 Markdown 编译为 React 组件
  • posthtml-loader 使用 PostHTML 加载并转换 HTML 文件
  • handlebars-loader 将 Handlebars 转移为 HTML
  • markup-inline-loader 将内联的 SVG/MathML 文件转换为 HTML。在应用于图标字体,或将 CSS 动画应用于 SVG 时很是有用。

4.3.五、样式

  • style-loader 将模块的导出做为样式添加到 DOM 中
  • css-loader 解析 CSS 文件后,使用 import 加载,而且返回 CSS 代码
  • less-loader 加载和转译 LESS 文件
  • sass-loader 加载和转译 SASS/SCSS 文件
  • postcss-loader 使用 PostCSS 加载和转译 CSS/SSS 文件
  • stylus-loader 加载和转译 Stylus 文件

4.3.六、清理和测试(Linting && Testing)

4.3.七、框架(Frameworks)

  • vue-loader 加载和转译 Vue 组件
  • polymer-loader 使用选择预处理器(preprocessor)处理,而且 require() 相似一等模块(first-class)的 Web 组件
  • angular2-template-loader 加载和转译 Angular 组件

4.四、raw-loader(文件原始内容转换器)

一个能够用于加载文件做为字符串使用的加载器,使用UTF-8编码。

安装

npm i --D raw-loader

 安装结果:

用法一:

经过 webpack 配置、命令行或者内联使用 loader。

复制代码
webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.txt$/,
                use: 'raw-loader'
            }
        ]
    }
}
复制代码

在你的项目中

import txt from './file.txt';

用法二:经过命令行(CLI)

webpack --module-bind 'txt=raw-loader'

用法三:在你的项目中

import txt from 'file.txt';

内联使用

import txt from 'raw-loader!./file.txt';

示例:

webpack.config.json

//webpack配置文件

//依赖node中的path模块
var path=require('path');

//定义一个默认模块对象
module.exports={
    //指定入口文件的位置,多入口
    entry:{
        index:"./src/index.js",
        main:"./src/main.js"
    },
    //设置输出结果
    output: {
        //路径,将相对路径转绝对路径
        path:path.resolve(__dirname,'dist'),
        //文件,[name]是模块名称,占位
        filename: "[name].bundle.js"
    },
    module: {  //模块处理
        rules: [ //处理器
            {
                test:/\.txt$/,  //当模块的后缀为.txt时匹配
                use: "raw-loader"  //模块转换器,能够以对象的形式指定参数
            }
        ]
    },
    mode: "development"
};
View Code

src/file1.txt

A loader for webpack that lets you import files as a string.

src/bar.js

复制代码
//定义模块
//部分依赖lodash中的join方法
import {join} from 'lodash';
//导入模块,得到file1.txt中的文件内容,被raw-loader处理
import message from './file1.txt';

//导出一个默认模块
export default function bar() {
    function component() {
        //建立DOM元素
        var element=document.createElement("h2");
        //使用join链接数组将结果写入元素的html中
        element.innerHTML=join(['Hello','Webpack','!'],' ')+"<br/>"+message;
        return element;
    }
    //在body中添加子元素
    document.body.appendChild(component());
}
复制代码

运行结果:

内联使用模块处理器:

4.五、CSS Loader(样式处理)

webpack提供两个工具处理样式表,css-loader 和 style-loader,两者处理的任务不一样,css-loader使你可以使用相似@import 和 url(...)的方法实现 require()的功能,style-loader将全部的计算后的样式加入页面中,两者组合在一块儿使你可以把样式表嵌入webpack打包后的JS文件中。

  • css-loader: 加载.css文件
  • style-loader:使用<style>将css-loader内部样式注入到咱们的HTML页面

css-loader详解:

https://www.npmjs.com/package/css-loader

https://www.webpackjs.com/loaders/css-loader/

style-loader详解:

https://www.npmjs.com/package/style-loader

https://www.webpackjs.com/loaders/style-loader/

4.5.一、安装

//安装
npm i style-loader css-loader -D

4.5.二、配置

复制代码
const path = require("path");

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: "bundle.js"
    },
    module: {
        rules: [
            {
                test:/\.css/,
                use:['style-loader',{
                    loader: 'css-loader',
                    options: {
                        sourceMap:true
                    }
                }]
            }
        ]
    },
    mode: "development"
};
复制代码

4.5.三、定义样式与引用

base.css

复制代码
h2{
    height: 40px;
    line-height: 40px;
    background: crimson;
    color:#fff;
}
复制代码

bar.js

复制代码
import {join} from 'lodash';
import base from '../css/base.css';

export default function bar() {
    function component() {
        var element=document.createElement("h2");
        element.innerHTML=join(['Hello','Webpack!']);
        return element;
    }
    document.body.appendChild(component());
}
复制代码

4.5.四、打包运行

打包:

运行:

生成代码:

4.5.五、注意事项

  1. rules里的数据类型为对象,每个loader都是一个对象
  2. test表示loader要处理什么类型的文件,这里用了一个正则去匹配文件类型
  3. use表示要使用哪一个loader,它的值是个数组,loader的使用顺序是从后往前
  4. 这个loader的意思为,在入口文件里找到.css类型的文件,先拿css-loader去处理成浏览器认识的css,再拿style-loader把处理后的css放在页面的style标签里

4.六、sass-loader(加载和转译 SASS/SCSS 文件)

加载sass或scss文件并转译成css

用css-loader或raw-loader 转换成一个JS模块或用ExtractTextPlugin插件将样式分隔成一个单独文件。

安装

npm i sass-loader node-sass --D

 

node-sass 和 webpack 是 sass-loader 的 peerDependency,所以可以精确控制它们的版本。

示例

css/baseScss.scss

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

 

经过将 style-loader 和 css-loader 与 sass-loader 链式调用,能够马上将样式做用在 DOM 元素。

配置webpack.config.json

复制代码
//webpack配置文件

//依赖node中的path模块
var path=require('path');

//定义一个默认模块对象
module.exports={
    //指定入口文件的位置,多入口
    entry:{
        index:"./src/index.js",
        main:"./src/main.js"
    },
    //设置输出结果
    output: {
        //路径,将相对路径转绝对路径
        path:path.resolve(__dirname,'dist'),
        //文件,[name]是模块名称,占位
        filename: "[name].bundle.js"
    },
    module: {  //模块处理
        rules: [ //处理器
            {
                test:/\.txt$/,  //当模块的后缀为.txt时匹配
                use: "raw-loader"  //模块转换器,能够以对象的形式指定参数
            },
            {
                test:/\.css$/,  //匹配全部css模块
                //use表示要使用哪一个loader,它的值是个数组,loader的使用顺序是从后往前
                use: ["style-loader",{
                    loader: "css-loader",  //转换器名称
                    options: {  //配置选项
                        modules:true,  //模块化
                        sourceMap:true  //是否生成调试文件
                    }
                }]  //使用多个模块转换器
            },
            {
                test: /\.scss$/,
                use: [{
                    loader: "style-loader" // 将 JS 字符串生成为 style 节点
                }, {
                    loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
                }, {
                    loader: "sass-loader" // 将 Scss 编译成 CSS
                }]
            }
        ]
    },
    mode: "development"
};
复制代码

 

导入scss做为模块

复制代码
//定义模块
//部分依赖lodash中的join方法
import {join} from 'lodash';
//导入模块,得到file1.txt中的文件内容,被raw-loader处理
import message from './file1.txt';
//导入样式文件
//import '../css/baseCss.css'
//导入预处理样式文件
import '../css/baseScss.scss'

//导出一个默认模块
export default function bar() {
    function component() {
        //建立DOM元素
        var element=document.createElement("h2");
        //使用join链接数组将结果写入元素的html中
        element.innerHTML=join(['Hello','Webpack','!'],' ')+"<br/>"+message;
        return element;
    }
    //在body中添加子元素
    document.body.appendChild(component());
}
复制代码

打包后运行结果:

一般,生产环境下比较推荐的作法是,使用 ExtractTextPlugin 将样式表抽离成专门的单独文件。这样,样式表将再也不依赖于 JavaScript:

复制代码
const ExtractTextPlugin = require("extract-text-webpack-plugin");

const extractSass = new ExtractTextPlugin({
    filename: "[name].[contenthash].css",
    disable: process.env.NODE_ENV === "development"
});

module.exports = {
    ...
        module
:
{
    rules: [{
        test: /\.scss$/,
        use: extractSass.extract({
            use: [{
                loader: "css-loader"
            }, {
                loader: "sass-loader"
            }],
// 在开发环境使用 style-loader
            fallback: "style-loader"
        })
    }]
}
,
plugins: [
    extractSass
]
}
;
复制代码

 

4.七、url-loader(路径处理器)

 Webpack 容许你在js文件中require图片 , 经过 url-loader和file-loader来预处理图片文件.

安装

npm install --save-dev url-loader file-loader

用法

url-loader 功能相似于 file-loader,可是在文件大小(单位 byte)低于指定的限制时,能够返回一个 DataURL。

import img from './image.png'

配置

复制代码
webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192
                        }
                    }
                ]
            }
        ]
    }
}
复制代码

示例

复制代码
var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1);

var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);
复制代码

5、插件plugins

 

5.一、单独提取CSS

运行后,在dist目录里只有两个文件,一个bundle.js一个index.html文件,并无css文件,同时打开index.html源码后也没有发现有css的内容。这是由于style-loader的做用,它把css一同打包到了js文件里,js文件在能过DOM动态建立style标签并添加到页面里。因此css的内容已经放到了index.bundle.js里。

 这种形式只有当文件内容很少的时候可使用,若是CSS的内容以及JS的内容很是的多,把两块都打包到一个文件里就会增长文件的体积,用户打开页面的时候下载速度会受影响,同时影响用户体验。这就须要把CSS文件单独拎出来,那须要一个插件来配合loader才能完成

mini-css-extract-plugin

webpack版本须要4.3以上,低版本请使用extract-text-webpack-plugin

使用步骤:

一、安装

npm i mini-css-extract-plugin -D

二、在webpack.config.js里引入模块

const MiniCssExtractPlugin=require("mini-css-extract-plugin");

三、写入plugins

plugins:[
new HtmlWebpackPlugin({
title:'tom',
template:'./src/template.html',
filename:'index.html',
}),
new MiniCssExtractPlugin({
filename:'css/index.css' //文件目录会放入output.path里
}),
]

四、写入loader

module:{
rules:[
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,"css-loader"] //代替style-loader
}
]
}

执行命令npm run build后能够看到dist目录里已经多了一个css文件夹,这个文件夹里放了一个index.css文件。打开index.html源码看到css文件已经经过link标签引入,这些功能都是mini-css-extract-plugin所作的

相关文章
相关标签/搜索