Skip to content

Commit

Permalink
Implementing SystemJSPublicPathWebpackPlugin. Resolves #12. (#14)
Browse files Browse the repository at this point in the history
* Implementing SystemJSPublicPathWebpackPlugin. Resolves #12.

* Self review

* Documenting Resource Query approach
  • Loading branch information
joeldenning authored Nov 30, 2020
1 parent cecbb99 commit 78308fc
Show file tree
Hide file tree
Showing 6 changed files with 4,116 additions and 3,748 deletions.
44 changes: 41 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,37 @@ npm install --save systemjs-webpack-interop
yarn add systemjs-webpack-interop
```

## Public Path
## Setting Public Path

systemjs-webpack-interop will [dynamically set the webpack public path](https://webpack.js.org/guides/public-path/#on-the-fly) based on the URL that a SystemJS module was downloaded from.

### Newer versions of webpack
### As a Webpack Plugin

You can set the public path by adding the SystemJSPublicPathWebpackPlugin.

```js
// webpack.config.js
const SystemJSPublicPathWebpackPlugin = require("systemjs-webpack-interop/SystemJSPublicPathWebpackPlugin");

module.exports = {
plugins: [
new SystemJSPublicPathWebpackPlugin({
// optional: defaults to 1
// If you need the webpack public path to "chop off" some of the directories in the current module's url, you can specify a "root directory level". Note that the root directory level is read from right-to-left, with `1` indicating "current directory" and `2` indicating "up one directory":
rootDirectoryLevel: 1,

// ONLY NEEDED FOR WEBPACK 1-4. Not necessary for webpack@5
systemjsModuleName: "@org-name/project-name"
})
]
};
```

### With Code

You can also set the public path with code inside of your webpack project.

#### Newer versions of webpack

If you're using at least webpack 5.0.0-beta.15, simply add the following **to the very top** of your [webpack entry file](https://webpack.js.org/configuration/entry-context/#entry):

Expand Down Expand Up @@ -67,7 +93,17 @@ import "systemjs-webpack-interop/auto-public-path/2";
import "systemjs-webpack-interop/auto-public-path/3";
```

### Older versions of webpack
#### Older versions of webpack

##### Resource Query approach

To set the webpack public path in older versions of webpack, add the following to the very top of your webpack entry file:

```js
import "systemjs-webpack-interop/resource-query-public-path?systemjsModuleName=@org-name/project-name";
```

##### Old approach

To set the webpack public path in older versions of webpack, you'll need to do two things:

Expand Down Expand Up @@ -107,6 +143,8 @@ If you need the webpack public path to "chop off" some of the directories in the
setPublicPath("foo", 2);
```

## API

### setPublicPath

#### Arguments
Expand Down
69 changes: 69 additions & 0 deletions SystemJSPublicPathWebpackPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const webpack = require("webpack");

const isWebpack5 = webpack.version && webpack.version.startsWith("5.");

class SystemJSPublicPathWebpackPlugin {
constructor(options) {
this.options = options || {};
if (!isWebpack5 && !this.options.systemjsModuleName) {
throw Error(
`SystemJSPublicPathWebpackPlugin: When using webpack@<5, you must provide 'systemjsModuleName' as an option.`
);
}
}
apply(compiler) {
const additionalEntries = [];

if (isWebpack5) {
additionalEntries.push(
`systemjs-webpack-interop/auto-public-path/${this.options
.rootDirectoryLevel || 1}`
);
} else {
additionalEntries.push(
`systemjs-webpack-interop/resource-query-public-path?systemjsModuleName=${this.options.systemjsModuleName}`
);
}

compiler.options.entry = prependEntry(
compiler.options.entry,
additionalEntries
);
}
}

// This function was copied from https://github.com/webpack/webpack-dev-server/blob/b0161e9852cdf41730e82aa43efe7e88f44a4f9d/lib/utils/DevServerPlugin.js#L72
function prependEntry(originalEntry, additionalEntries) {
if (typeof originalEntry === "function") {
return () =>
Promise.resolve(originalEntry()).then(entry =>
prependEntry(entry, additionalEntries)
);
}

if (typeof originalEntry === "object" && !Array.isArray(originalEntry)) {
/** @type {Object<string,string>} */
const clone = {};

Object.keys(originalEntry).forEach(key => {
// entry[key] should be a string here
const entryDescription = originalEntry[key];
clone[key] = prependEntry(entryDescription, additionalEntries);
});

return clone;
}

// in this case, entry is a string or an array.
// make sure that we do not add duplicates.
/** @type {Entry} */
const entriesClone = additionalEntries.slice(0);
[].concat(originalEntry).forEach(newEntry => {
if (!entriesClone.includes(newEntry)) {
entriesClone.push(newEntry);
}
});
return entriesClone;
}

module.exports = SystemJSPublicPathWebpackPlugin;
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@
"jest-cli": "^25.1.0",
"prettier": "^1.19.1",
"pretty-quick": "^2.0.1"
},
"peerDependencies": {
"webpack": "*"
}
}
Loading

0 comments on commit 78308fc

Please sign in to comment.