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

Allow arbitrary file names for webpack_path helper/tag #247

Merged
merged 3 commits into from
Mar 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 57 additions & 28 deletions bridgetown-core/features/webpack_path_tag.feature
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,47 @@ Feature: WebpackPath Tag
And I have an "index.html" page with layout "default" that contains "page content"
And I have a ".bridgetown-webpack" directory
And I have a ".bridgetown-webpack/manifest.json" file with content:
"""
{
"main.js": "all.hashgoeshere.js",
"main.css": "all.hashgoeshere.css"
}
"""
"""
{
"main.js": "all.hashgoeshere.js",
"main.css": "all.hashgoeshere.css"
}
"""
When I run bridgetown build
Then the "output/index.html" file should exist
And I should see "/_bridgetown/static/js/all.hashgoeshere.js" in "output/index.html"
And I should not see "//_bridgetown/static/js/all.hashgoeshere.js" in "output/index.html"
And I should not see "MISSING_WEBPACK_MANIFEST" in "output/index.html"

Scenario: Use custom filename in Webpack manifest
Given I have a _layouts directory
And I have a "_layouts/default.html" file with content:
"""
<html>
<head>
<link rel="stylesheet" href="{% webpack_path css %}" />
<link rel="preload" href="{% webpack_path images/folder/somefile.png %}" />
</head>
<body>
{{ content }}
</body>
</html>
"""
And I have an "index.html" page with layout "default" that contains "page content"
And I have a ".bridgetown-webpack" directory
And I have a ".bridgetown-webpack/manifest.json" file with content:
"""
{
"main.js": "all.hashgoeshere.js",
"main.css": "all.hashgoeshere.css",
"../frontend/images/folder/somefile.png": "../frontend/images/folder/somefile.hashgoeshere.png"
}
"""
When I run bridgetown build
Then the "output/index.html" file should exist
And I should see "/_bridgetown/static/frontend/images/folder/somefile.hashgoeshere.png" in "output/index.html"
And I should not see "MISSING_WEBPACK_MANIFEST" in "output/index.html"

Scenario: Missing Webpack manifest
Given I have a _layouts directory
And I have a "_layouts/default.html" file with content:
Expand Down Expand Up @@ -67,12 +96,12 @@ Feature: WebpackPath Tag
And I have an "index.html" page with layout "default" that contains "page content"
And I have a ".bridgetown-webpack" directory
And I have a ".bridgetown-webpack/manifest.json" file with content:
"""
{
"main.js": "all.hashgoeshere.js",
"main.css": "all.hashgoeshere.css"
}
"""
"""
{
"main.js": "all.hashgoeshere.js",
"main.css": "all.hashgoeshere.css"
}
"""
When I run bridgetown build
Then the "output/index.html" file should exist
And I should see "Unknown Webpack asset type" in the build output
Expand All @@ -94,11 +123,11 @@ Feature: WebpackPath Tag
And I have an "index.html" page with layout "default" that contains "page content"
And I have a ".bridgetown-webpack" directory
And I have a ".bridgetown-webpack/manifest.json" file with content:
"""
{
"main.js": "all.hashgoeshere.js"
}
"""
"""
{
"main.js": "all.hashgoeshere.js"
}
"""
When I run bridgetown build
Then the "output/index.html" file should exist
And I should see "WebpackAssetError" in the build output
Expand All @@ -120,11 +149,11 @@ Feature: WebpackPath Tag
And I have an "index.html" page with layout "default" that contains "page content"
And I have a ".bridgetown-webpack" directory
And I have a ".bridgetown-webpack/manifest.json" file with content:
"""
{
"main.css": "all.hashgoeshere.css"
}
"""
"""
{
"main.css": "all.hashgoeshere.css"
}
"""
When I run bridgetown build
Then the "output/index.html" file should exist
And I should see "WebpackAssetError" in the build output
Expand All @@ -147,12 +176,12 @@ Feature: WebpackPath Tag
And I have an "index.html" page with layout "default" that contains "page content"
And I have a ".bridgetown-webpack" directory
And I have a ".bridgetown-webpack/manifest.json" file with content:
"""
{
"main.js": "all.hashgoeshere.js",
"main.css": "all.hashgoeshere.css"
}
"""
"""
{
"main.js": "all.hashgoeshere.js",
"main.css": "all.hashgoeshere.css"
}
"""
When I run bridgetown build
Then the "output/index.html" file should exist
And I should see "/_bridgetown/static/js/all.hashgoeshere.js" in "output/index.html"
Expand Down
27 changes: 18 additions & 9 deletions bridgetown-core/lib/bridgetown-core/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ def reindent_for_markdown(input)

# Return an asset path based on the Webpack manifest file
# @param site [Bridgetown::Site] The current site object
# @param asset_type [String] js or css
# @param asset_type [String] js or css, or filename in manifest
#
# @return [String] Returns "MISSING_WEBPACK_MANIFEST" if the manifest
# file isnt found
Expand All @@ -363,21 +363,30 @@ def parse_webpack_manifest_file(site, asset_type)
manifest = JSON.parse(File.read(manifest_file))

known_assets = %w(js css)
asset_path = nil
if known_assets.include?(asset_type)
asset_path = manifest["main.#{asset_type}"]

log_webpack_asset_error(asset_type) && return if asset_path.nil?

asset_path = asset_path.split("/").last
return [static_frontend_path(site), asset_type, asset_path].join("/")
else
asset_path = manifest.find do |item, _|
item.sub(%r{^../(frontend/|src/)?}, "") == asset_type
end&.last
end

Bridgetown.logger.error("Unknown Webpack asset type", asset_type)
nil
if asset_path
static_frontend_path(site, ["js", asset_path])
else
Bridgetown.logger.error("Unknown Webpack asset type", asset_type)
nil
end
end

def static_frontend_path(site)
path_parts = [site.config["baseurl"].to_s.chomp("/"), "_bridgetown/static"]
def static_frontend_path(site, additional_parts = [])
path_parts = [
site.config["baseurl"].to_s.gsub(%r(^/|/$), ""),
"_bridgetown/static",
*additional_parts,
]
path_parts[0] = "/#{path_parts[0]}" unless path_parts[0].empty?
Addressable::URI.parse(path_parts.join("/")).normalize.to_s
end
Expand Down
14 changes: 8 additions & 6 deletions bridgetown-core/lib/site_template/webpack.config.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ManifestPlugin = require("webpack-manifest-plugin");

module.exports = {
entry: "./frontend/javascript/index.js",
entry: {
main: "./frontend/javascript/index.js"
},
devtool: "source-map",
// Set some or all of these to true if you want more verbose logging:
stats: {
Expand All @@ -14,7 +16,7 @@ module.exports = {
},
output: {
path: path.resolve(__dirname, "output", "_bridgetown", "static", "js"),
filename: "all.[contenthash].js",
filename: "[name].[contenthash].js",
},
resolve: {
extensions: [".js", ".jsx"],
Expand All @@ -29,7 +31,7 @@ module.exports = {
},
plugins: [
new MiniCssExtractPlugin({
filename: "../css/all.[contenthash].css",
filename: "../css/[name].[contenthash].css",
}),
new ManifestPlugin({
fileName: path.resolve(__dirname, ".bridgetown-webpack", "manifest.json"),
Expand Down Expand Up @@ -108,9 +110,9 @@ module.exports = {
test: /\.png?$|\.gif$|\.jpg$|\.svg$/,
loader: "file-loader",
options: {
name: "[name]-[contenthash].[ext]",
outputPath: "../images",
publicPath: "../images",
name: "[path][name]-[contenthash].[ext]",
outputPath: "../",
publicPath: "../",
},
},
],
Expand Down
45 changes: 33 additions & 12 deletions bridgetown-website/src/_docs/frontend-assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ top_section: Content
category: frontendassets
---

Bridgetown comes with a default configuration of [Webpack](https://webpack.js.org) to handle building and exporting frontend assets such as Javascript/Typescript/etc., CSS/Sass/etc., and related files that are imported through Webpack (fonts, icons, etc.)
Bridgetown comes with a default configuration of [Webpack](https://webpack.js.org) to handle building and exporting frontend assets such as JavaScript/TypeScript/etc., CSS/Sass/etc., and related files that are imported through Webpack (fonts, icons, etc.)

Files to be processed by Webpack are placed in the top-level `frontend` folder within your site root. This folder is entirely separate from the Bridgetown source folder where your content, templates, plugins, etc. live. However, using relative paths you can reference files from Webpack that live in the source folder (so you could keep CSS partials alongside Liquid templates, for example).

{% rendercontent "docs/note" %}
Wondering where to save images? Look at the `src/images` folder. You can reference them from both markup and CSS simply using a relative URL (for example, `/images/logo.svg`). Optionally, you can bundle images through Webpack's `css-loader` (more information below). If you're interested in a full-featured image management solution with the ability to resize and optimize your media sizes, check out [Cloudinary](https://www.cloudinary.com){:rel="noopener"} and the [bridgetown-cloudinary plugin](https://github.com/bridgetownrb/bridgetown-cloudinary){:rel="noopener"}.
Wondering where to save images? Look at the `src/images` folder. You can reference them from both markup and CSS simply using a relative URL (for example, `/images/logo.svg`). Optionally, you can bundle images through Webpack and reference them with the `webpack_path` helper (more information below). If you're interested in a full-featured image management solution with the ability to resize and optimize your media sizes, check out [Cloudinary](https://www.cloudinary.com){:rel="noopener"} and the [bridgetown-cloudinary plugin](https://github.com/bridgetownrb/bridgetown-cloudinary){:rel="noopener"}.
{% endrendercontent %}

Bridgetown uses [Yarn](https://yarnpkg.com){:rel="noopener"} to install and manage frontend NPM-based packages and dependencies. [Gem-based plugins can instruct Bridgetown](/docs/plugins/gems-and-webpack/) to add a related NPM package whenever Bridgetown first loads the gem.

{% toc %}

## Javascript
## JavaScript

The starting place for Javascript code lives at `./frontend/javascript/index.js`. Here you can write your custom functionality, use `import` statements to pull in other modules or external packages, and so forth. This is also where you'd import all relevant CSS. (By default it imports `./frontend/styles/index.scss`.)
The starting place for JavaScript code lives at `./frontend/javascript/index.js`. Here you can write your custom functionality, use `import` statements to pull in other modules or external packages, and so forth. This is also where you'd import all relevant CSS. (By default it imports `./frontend/styles/index.scss`.)

Because Bridgetown utilizes standard Webpack functionality, you can trick out your Javascript setup with additional language enhancements like Typescript or add well-known frameworks like [LitElement](https://lit-element.polymer-project.org), [Stimulus](https://stimulusjs.org), [Alpine](https://github.com/alpinejs/alpine/), [React](https://reactjs.org), [Vue](https://vuejs.org), and many others. For example, to add slick page transitions to your website using [Swup](https://swup.js.org/), you would simply run:
Because Bridgetown utilizes standard Webpack functionality, you can trick out your JavaScript setup with additional language enhancements like TypeScript or add well-known frameworks like [LitElement](https://lit-element.polymer-project.org), [Stimulus](https://stimulusjs.org), [Alpine](https://github.com/alpinejs/alpine/), [React](https://reactjs.org), [Vue](https://vuejs.org), and many others. For example, to add slick page transitions to your website using [Swup](https://swup.js.org/), you would simply run:

```sh
yarn add swup
Expand Down Expand Up @@ -57,7 +57,7 @@ And then adding:
@import "~css-framework/css-framework";
```

to `index.scss`. For example, to add [Bulma](https://bulma.io) which is a modern CSS-only (no Javascript) framework built around Flexbox, you'd simply run:
to `index.scss`. For example, to add [Bulma](https://bulma.io) which is a modern CSS-only (no JavaScript) framework built around Flexbox, you'd simply run:

```shell
$ yarn add bulma
Expand Down Expand Up @@ -106,7 +106,7 @@ The popular [TailwindCSS](https://tailwindcss.com) framework can be added to you

Bridgetown's default Webpack configuration is set up to place all compiled output into the `_bridgetown` folder in your `output` folder. Bridgetown knows when it regenerates a website not to touch anything in `_bridgetown` as that comes solely from Webpack. It is recommended you do not use the site source folder to add anything to `_bridgetown` as that will not get cleaned and updated by Bridgetown's generation process across multiple builds.

To reference the compiled JS and CSS files from Webpack in your site template, simply add the `webpack_path` Liquid tag to your HTML `<head>`:
To reference the compiled JS and CSS files from Webpack in your site template, simply add the `webpack_path` Liquid tag or Ruby helper to your HTML `<head>`. For example:

{% raw %}
```liquid
Expand All @@ -124,7 +124,7 @@ This will automatically produce HTML tags that look something like this:

## Additional Bundled Assets (Fonts, Images)

By default starting with Bridgetown 0.19.3, both fonts and images can be bundled through Webpack's loaders. This means that, in CSS/JS files, you can reference fonts/images saved somewhere in the `frontend` folder (or even from a package in `node_modules`) and those will get transformed and copied over to `output/_bridgetown` within an appropriate subfolder and with a hashed filename (aka `photo.jpg` would become `photo-31d6cfe0d16ae931b73c59d7e0c089c0.jpg`).
By default starting with Bridgetown 0.20, both fonts and images can be bundled through Webpack's loaders. This means that, in CSS/JS files, you can reference fonts/images saved somewhere in the `frontend` folder (or even from a package in `node_modules`) and those will get transformed and copied over to `output/_bridgetown` within an appropriate subfolder and with a hashed filename (aka `photo.jpg` would become `photo-31d6cfe0d16ae931b73c59d7e0c089c0.jpg`).

There's a catch with regard to how this works, because you'll also want to be able to save files directly within `src` that are accessible via standard relative URLs (so `src/images/photo.jpg` is available at `/images/photo.jpg` within the static output, no Webpack processing required).

Expand All @@ -134,8 +134,29 @@ There's a catch with regard to how this works, because you'll also want to be ab
* For any files saved inside of `frontend`, use filesystem-relative paths. For example: `background: url("../images/photo.jpg")` in `frontend/styles/index.css` will look for `frontend/images/photo.jpg`. If the file can't be found, Webpack will throw an error.
* For a Node package file, use Webpack's special `~` character, aka `~package-name/path/to/image.jpg`.

When bundling, Webpack will place image files (jpg, png, gif, svg) in `output/_bridgetown/static/images` and font files (woff, woff2, eot, ttf) in `output/_bridgetown/static/fonts`. You can edit `webpack.config.js` if you wish to change this default behavior.
When bundling, Webpack will place image files (jpg, png, gif, svg) in `output/_bridgetown/static/path/to/image.ext` and font files (woff, woff2, eot, ttf) in `output/_bridgetown/static/fonts`. You can edit `webpack.config.js` if you wish to change this default behavior.

{% rendercontent "docs/note", extra_margin: true, title: "There's more to the story…" %}
In a future version of Bridgetown, a Liquid tag/Ruby helper will be provided to allow you to reference image URLs via the Webpack manifest, so in theory you could use Webpack to manage _all_ of your image files (instead of saving them in `src`). But for now, Webpack-managed images/fonts are only useful within the context of CSS-based URLs.
{% endrendercontent %}
You can also use the `webpack_path` Liquid tag/Ruby helper to reference assets as well.

{% raw %}
```liquid
<img src="{% webpack_path images/folder/somefile.png %}" />
```

## Multiple Entry Points

If you need to manage more than one Webpack bundle, you can add additional entry points to the `webpack.config.js` file (in Bridgetown 0.20 and above). For example:

```js
entry: {
main: "./frontend/javascript/index.js",
something_else: "./frontend/otherscript/something_else.js"
},
```

Then simply reference the entry point filename via `webpack_path` wherever you'd like to load it in your HTML:

```liquid
<script src="{% webpack_path something_else.js %}"></script>
```
{% endraw %}
2 changes: 1 addition & 1 deletion bridgetown-website/src/_docs/static_files.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ include images, PDFs, and other un-rendered content.
You can save static files in any subfolder or directly within the source folder (`src`). A common place to save images specifically is the `src/images` folder. You can reference them from both markup and CSS simply using a relative URL (for example, `/images/logo.svg`).

{% rendercontent "docs/note" %}
If you're interested in a full-featured image management solution with the ability to resize and optimize your media sizes, check out [Cloudinary](https://www.cloudinary.com){:rel="noopener"} and the [bridgetown-cloudinary plugin](https://github.com/bridgetownrb/bridgetown-cloudinary){:rel="noopener"}.
Optionally, you can [bundle images through Webpack](/docs/frontend-assets) and reference them with the `webpack_path` helper. Or if you're interested in a full-featured image management solution with the ability to resize and optimize your media sizes, check out [Cloudinary](https://www.cloudinary.com){:rel="noopener"} and the [bridgetown-cloudinary plugin](https://github.com/bridgetownrb/bridgetown-cloudinary){:rel="noopener"}.
{% endrendercontent %}

Static files can be searched and accessed in templates via `site.static_files` and contain the
Expand Down