学习包-用于小型项目的Webpack替代品





朋友们,美好的一天!



模块构建器或捆绑程序(例如Webpack或Parcel)的主要目的是确保以正确的顺序以索引中包含的一个缩小的(对于生产构建)脚本包含运行应用程序所需的所有模块。 html。



实际上,构建者通常不仅可以优化JS,而且可以优化HTML,CSS文件,可以将Less,Sass转换为CSS,TypeScript,React和Vue(JSX)转换为JavaScript,并可以处理图像,音频,视频等。数据格式,还提供其他功能,例如:创建(使用的)资源或源的图(源图),整个包及其单个部分(模块,库)的大小的可视化表示,将代码划分为多个部分(块),包括数字,以供重用(例如,将在多个模块中使用的库从一个单独的文件中取出并仅加载一次),从npm智能加载软件包(例如,仅从moment.js加载俄语本地化),用于解决特定任务的各种插件等等



在这方面,领导当然属于Webpack。但是,如果我们正在开发一个不需要该强大工具提供的大多数功能的项目该怎么办?是否有此技术的替代方法更易于学习和使用?对我来说,这个问题的答案是包裹。顺便说一句,如果您有兴趣学习Webpack,建议您观看此视频。我的本教程的Webpack设置文件位于此处



















在您允许的情况下,我不会用自己的语言来讲述文档,尤其是因为该文档以俄语提供,但我将专注于实用的组件,即:使用模板字符串和动态导入,我们将创建一个由JavaScript组成的SPA,其中包含三个页面,使用CSS设置应用程序样式,在TypeScript中编写一个简单函数,将其导入应用程序,使用Sass为该函数的结果设置容器样式,并在开发和生产模式下均使用Parcel构建应用程序。



项目代码在这里



如果您有兴趣,请关注我。



应用



准备?那我们走吧



创建地块教程目录。



我们进入其中,并使用初始化项目npm init -y



创建index.html文件。我们将使用标准的Bootstrap Cover模板之一:



<head>
    ...
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>

<!-- Bootstrap class -->
<body class="text-center">

    <! -- Main script -->
    <script src="index.js"></script>
</body>


转到Bootstrap官方网站,转到“示例”部分,在“自定义”组件中找到Cover,按Ctrl + U(Cmd + U)查看页面代码。











创建src目录,其中还有两个文件夹-js和css。



在js目录中创建以下文件:header.js,footer.js,home.js,projects.js和contact.js。这些是我们应用程序的模块或组件,如果您愿意,它们是:页眉,页脚,主页内容和其他页面。



在css目录中,创建一个style.css文件。



目前,项目结构如下所示:



-- parcel-tutorial
    -- src
        -- css
            -- style.css
        -- js
            -- contact.js
            -- footer.js
            -- header.js
            -- home.js
            -- projects.js
    -- index.html
    -- index.js
    -- package.json


返回引导程序。



稍作更改,将页面代码复制粘贴到相应的模块中。



header.js:



export default `
  <header class="masthead mb-auto">
      <div class="inner">
          <h3 class="masthead-brand">Parcel Tutorial</h3>
          <nav class="nav nav-masthead justify-content-center">
            <a class="nav-link active" name="home">Home</a>
            <a class="nav-link" name="projects">Projects</a>
            <a class="nav-link" name="contact">Contact</a>
        </nav>
      </div>
  </header>
`.trim()


请注意,我们已将href更改为链接中的名称。



footer.js:



export default `
  <footer class="mastfoot mt-auto">
    <div class="inner">
      <p>© 2020. All rights reserved.</p>
    </div>
  </footer>
`.trim()


home.js:



export default `
  <h1 class="cover-heading">Home page</h1>
  <p class="lead">Home page content</p>
`.trim()


projects.js:



export default `
  <h1 class="cover-heading">Projects page</h1>
  <p class="lead">Projects page content</p>
`.trim()


contact.js:



export default `
  <h1 class="cover-heading">Contact page</h1>
  <p class="lead">Contact page content</p>
`.trim()


不要忘记将样式从cover.css复制到style.css。



打开index.js。



让我们导入页眉,页脚和样式:



import header from './src/js/header.js'
import footer from './src/js/footer.js'
import './src/css/style.css'


单击链接后,将动态加载主页和其他页面的内容,因此我们创建了一个像这样的对象:



const pages = {
    home: import('./src/js/home.js'),
    projects: import('./src/js/projects.js'),
    contact: import('./src/js/contact.js')
}


该对象的属性名称是相应的页面(由用户请求)。



我们使用先前导入的页眉和页脚组件生成起始页:



// Bootstrap classes
document.body.innerHTML = `
<div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
    ${header}
    <main role="main" class="inner cover"></main>
    ${footer}
</div>
`.trim()


页面的内容将显示在主要元素中,因此我们对其进行定义:



const mainEl = document.querySelector('main')


创建页面渲染功能:



const renderPage = async name => {
    const template = await pages[name]
    mainEl.innerHTML = template.default
}


我们需要等待相应的模块加载,因此我们使用async / await(await关键字暂停了函数的执行)。该函数获取所请求页面的名称(名称),并使用它来访问页面对象(页面[名称])的相应属性。然后,我们将生成的模板插入mainEl。实际上,await返回包含模板的Module对象。因此,当在mainEl中插入模板作为标记时,必须引用Module对象的默认属性(默认情况下会导出模块),否则,我们将收到错误消息-无法将对象转换为HTML。



渲染主页:



renderPage('home')


当前页面对应的活动链接具有活动类。呈现新页面时,我们需要切换类。让我们实现助手功能:



const toggleClass = (activeLink, currentLink) => {
    if (activeLink === currentLink) {
        return;
    } else {
        activeLink.classList.remove('active')
        currentLink.classList.add('active')
    }
}


该函数有两个参数-具有活动类的链接(activeLink)和被单击的链接(currentLink)。如果指定的链接匹配,我们什么也不做。否则,请更改类。



最后,我们需要添加链接点击处理程序。让我们再实现一个辅助函数:



const initClickHandlers = () => {
    const navEl = document.querySelector('nav')

    navEl.addEventListener('click', ev => {
        if (ev.target.tagName === 'A') {
            const activeLink = navEl.querySelector('.active')
            const currentLink = ev.target
            toggleClass(activeLink, currentLink)
            renderPage(currentLink.name)
        }
    })
}


在此功能中,我们首先找到nav元素。然后,通过委派,我们处理链接单击:如果目标元素是标签A,则获得活动链接(与活动类的链接),当前链接(被单击的链接),更改类并呈现页面。当前链接的name属性值作为renderPage参数传递。



我们几乎完成了该应用程序。但是,在继续使用Parcel构建项目之前,需要注意以下几点:今天,根据“我可以使用数据”对动态模块的支持为90%。数量很多,但我们还不准备失去10%的用户。因此,我们的代码需要转换为不太现代的语法。通天塔用于移植。我们需要连接两个附加模块:



import "core-js/stable";
import "regenerator-runtime/runtime";


请注意,我们不使用npm安装这些软件包。



另外,让我们立即在TypeScript中实现一个函数,它非常简单,例如用于将两个数字相加的函数。



在js目录中创建具有以下内容的index.ts文件:



export const sum = (a: number, b: number): number => a + b


除了文件扩展名(.ts)之外,与JavaScript的唯一区别是我们明确指定了函数接受和返回的值的类型-在这种情况下为数字。实际上,我们可以将自己限制为定义返回类型,TypeScript足够聪明,可以理解如果返回值是数字,则传递的参数必须是数字。没关系。



让我们将此函数导入index.js:



import { sum } from './src/js/index.ts'


并在renderPage中使用参数1和2调用它:



const renderPage = async name => {
    // ...
    mainEl.insertAdjacentHTML('beforeend', `
        <output>Result of 1 + 2 -> <span>${sum(1, 2)}<span></output>
    `)
}


使用Sass对功能结果容器进行样式设置。在css文件夹中,创建具有以下内容的style.scss文件:



$color: #8e8e8e;

output {
    color: $color;
    border: 1px solid $color;
    border-radius: 4px;
    padding: .5rem;
    user-select: none;
    transition: transform .2s;

    & span {
        color: #eee;
    }

    &:hover {
        transform: scale(1.1);
    }
}


让我们将这些样式导入index.js:



import './src/css/style.scss'


再次注意,我们不使用npm安装TypeScript和Sass。



我们完成了申请。转到包裹。





要全局安装Parcel,您需要npm i parcel-bundler -g在终端中运行命令



打开package.json并将Parcel配置为在开发和生产模式下运行:



"scripts": {
    "dev": "parcel index.html --no-source-maps --open",
    "pro": "parcel build index.html --no-source-maps --no-cache"
  },


团队npm run dev开始构建项目进行开发,然后团队开始npm run pro进行生产。但是所有这些标志是什么意思?为什么我们不通过npm安装Babel,TypeScript和Sass?



事实是,Parcel在检测到它们的导入或在应用程序中的使用时会自动安装所有依赖项。例如,如果Parcel看到从.scss文件导入的样式表,则它将安装Sass。



现在介绍球队和旗帜。



要以开发模式构建项目,请使用命令parcel index.html,其中index.html是应用程序的入口点,即包含指向一个或多个主脚本的链接的文件。另外,此命令还会在本地主机1234上启动本地服务器。



该标志--no-source-maps意味着我们不需要资源映射。



--open告诉Parcel在本地服务器上的浏览器中构建后打开index.html。



要以生产方式构建项目,请使用命令parcel build index.html。该程序集假定JS,CSS和HTML文件的最小化。



该标志--no-cache意味着禁用资源缓存。高速缓存可以实时地快速构建和重建项目。这在开发时很重要,但在组装成品时并不过分。



还有一点:默认情况下,Parcel将生成的文件放在dist文件夹中,如果缺少该文件夹,则会创建该文件夹。问题在于,重建时不会删除旧文件。要删除这些文件,您需要一个特殊的插件,例如parcel-plugin-clean-easy



使用安装此插件npm i parcel-plugin-clean-easy -D 并将以下内容添加到package.json中:



"parcelCleanPaths": [
    "dist",
    ".cache"
  ]


parcelCleanPaths是要在重建时删除的目录。



包裹现已完全配置。打开一个终端,键入npm run dev,然后按Enter。















Parcel以开发模式构建项目,启动本地服务器,然后在浏览器中打开应用程序。优秀的。



现在,让我们尝试将一个生产项目组合在一起。



我们执行命令npm run pro











我们在浏览器中启动该应用程序。







糟糕,好像出了点问题。



让我们看一下生成的index.html。我们在那里看到什么?提示:请注意链接和脚本标签中的路径。我不确切知道这和什么有关,但是Parcel将相对链接转换为“ / path-to-file”,并且浏览器无法读取此类链接。



为了解决此问题,您需要在“ pro”脚本中添加“ --public-url。”标志。



我们开始重建。



相对路径正确,应用程序可以正常工作。凉。







这就是我的全部。感谢您的关注。



All Articles